From 1394cf13cd6528773e02a54f855d101fe49f991e Mon Sep 17 00:00:00 2001 From: water Date: Mon, 7 Sep 2020 19:17:48 -0400 Subject: [PATCH] 17 of 124 compiler tests passing --- game/kernel/kscheme.cpp | 1 - goal_src/test/test-defglobalconstant-1.gc | 5 + goal_src/test/test-defglobalconstant-2.gc | 8 ++ goal_src/test/test-goto-1.gc | 9 ++ goal_src/test/test-nested-blocks-1.gc | 11 ++ goal_src/test/test-nested-blocks-2.gc | 11 ++ goal_src/test/test-nested-blocks-3.gc | 11 ++ goalc/compiler/Compiler.cpp | 1 + goalc/compiler/Compiler.h | 8 ++ goalc/compiler/Env.cpp | 42 ++++++- goalc/compiler/Env.h | 33 +++++- goalc/compiler/IR.cpp | 71 ++++++++++++ goalc/compiler/IR.h | 30 +++++ goalc/compiler/Label.h | 11 +- goalc/compiler/Util.cpp | 14 +++ goalc/compiler/compilation/Atoms.cpp | 25 ++++- goalc/compiler/compilation/Block.cpp | 129 ++++++++++++++++++++++ goalc/compiler/compilation/Macro.cpp | 28 +++++ goalc/emitter/ObjectGenerator.cpp | 9 ++ goalc/emitter/ObjectGenerator.h | 1 + test/test_compiler_and_runtime.cpp | 6 + 21 files changed, 449 insertions(+), 15 deletions(-) create mode 100644 goal_src/test/test-defglobalconstant-1.gc create mode 100644 goal_src/test/test-defglobalconstant-2.gc create mode 100644 goal_src/test/test-goto-1.gc create mode 100644 goal_src/test/test-nested-blocks-1.gc create mode 100644 goal_src/test/test-nested-blocks-2.gc create mode 100644 goal_src/test/test-nested-blocks-3.gc diff --git a/game/kernel/kscheme.cpp b/game/kernel/kscheme.cpp index bec0f1be1..816918ff0 100644 --- a/game/kernel/kscheme.cpp +++ b/game/kernel/kscheme.cpp @@ -960,7 +960,6 @@ uint64_t _call_goal_asm_win32(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, u64 call_goal(Ptr f, u64 a, u64 b, u64 c, u64 st, void* offset) { // auto st_ptr = (void*)((uint8_t*)(offset) + st); updated for the new compiler! void* st_ptr = (void*)st; - printf("st is 0x%x\n", st); void* fptr = f.c(); #ifdef __linux__ diff --git a/goal_src/test/test-defglobalconstant-1.gc b/goal_src/test/test-defglobalconstant-1.gc new file mode 100644 index 000000000..ce99baba6 --- /dev/null +++ b/goal_src/test/test-defglobalconstant-1.gc @@ -0,0 +1,5 @@ +(defglobalconstant my-constant 12) +(defglobalconstant my-constant 17) +(defglobalconstant not-my-consant 13) + +my-constant \ No newline at end of file diff --git a/goal_src/test/test-defglobalconstant-2.gc b/goal_src/test/test-defglobalconstant-2.gc new file mode 100644 index 000000000..781eae407 --- /dev/null +++ b/goal_src/test/test-defglobalconstant-2.gc @@ -0,0 +1,8 @@ +(defmacro get-goos-by-name (name) + ;; do the lookup in the goos global environment + (eval name) + ) + +(defglobalconstant my-constant 18) + +(get-goos-by-name my-constant) \ No newline at end of file diff --git a/goal_src/test/test-goto-1.gc b/goal_src/test/test-goto-1.gc new file mode 100644 index 000000000..b310f6789 --- /dev/null +++ b/goal_src/test/test-goto-1.gc @@ -0,0 +1,9 @@ + + +(block my-block + 1 + (goto skip-early-return) + (return-from my-block 2) + (label skip-early-return) + 3 + ) diff --git a/goal_src/test/test-nested-blocks-1.gc b/goal_src/test/test-nested-blocks-1.gc new file mode 100644 index 000000000..00bc13bca --- /dev/null +++ b/goal_src/test/test-nested-blocks-1.gc @@ -0,0 +1,11 @@ +(block outer-block + 1 + 2 + (block inner-block + 3 + 4 + (return-from inner-block 7) + 5 + 6 + ) + ) \ No newline at end of file diff --git a/goal_src/test/test-nested-blocks-2.gc b/goal_src/test/test-nested-blocks-2.gc new file mode 100644 index 000000000..f421a2027 --- /dev/null +++ b/goal_src/test/test-nested-blocks-2.gc @@ -0,0 +1,11 @@ +(block outer-block + 1 + 2 + (block inner-block + 3 + 4 + (return-from inner-block 7) + 5 + ) + 8 + ) \ No newline at end of file diff --git a/goal_src/test/test-nested-blocks-3.gc b/goal_src/test/test-nested-blocks-3.gc new file mode 100644 index 000000000..cd1e3b188 --- /dev/null +++ b/goal_src/test/test-nested-blocks-3.gc @@ -0,0 +1,11 @@ +(block outer-block + 1 + 2 + (block inner-block + 3 + 4 + (return-from outer-block 7) + 5 + ) + 8 + ) \ No newline at end of file diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index a72875317..29c5c4d95 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -203,5 +203,6 @@ void Compiler::typecheck(const goos::Object& form, const TypeSpec& expected, const TypeSpec& actual, const std::string& error_message) { + (void)form; m_ts.typecheck(expected, actual, error_message, true, true); } \ No newline at end of file diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 9f49720f3..215ee61f0 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -53,6 +53,9 @@ class Compiler { named); std::string as_string(const goos::Object& o); std::string symbol_string(const goos::Object& o); + const goos::Object& pair_car(const goos::Object& o); + const goos::Object& pair_cdr(const goos::Object& o); + void expect_empty_list(const goos::Object& o); TypeSystem m_ts; std::unique_ptr m_global_env = nullptr; @@ -75,6 +78,10 @@ class Compiler { // Block Val* compile_begin(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_top_level(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_block(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_return_from(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_label(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_goto(const goos::Object& form, const goos::Object& rest, Env* env); // CompilerControl Val* compile_seval(const goos::Object& form, const goos::Object& rest, Env* env); @@ -90,6 +97,7 @@ class Compiler { // Macro Val* compile_gscond(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_quote(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_defglobalconstant(const goos::Object& form, const goos::Object& rest, Env* env); }; #endif // JAK_COMPILER_H diff --git a/goalc/compiler/Env.cpp b/goalc/compiler/Env.cpp index 50bc15328..0114dca60 100644 --- a/goalc/compiler/Env.cpp +++ b/goalc/compiler/Env.cpp @@ -47,6 +47,10 @@ RegVal* Env::make_xmm(TypeSpec ts) { return make_ireg(std::move(ts), emitter::RegKind::XMM); } +std::unordered_map& Env::get_label_map() { + return parent()->get_label_map(); +} + /////////////////// // GlobalEnv /////////////////// @@ -123,6 +127,24 @@ void NoEmitEnv::emit(std::unique_ptr ir) { throw std::runtime_error("emit into a no-emit env!"); } +/////////////////// +// BlockEnv +/////////////////// + +BlockEnv::BlockEnv(Env* parent, std::string _name) : Env(parent), name(std::move(_name)) {} + +std::string BlockEnv::print() { + return "block-" + name; +} + +BlockEnv* BlockEnv::find_block(const std::string& block) { + if (name == block) { + return this; + } else { + return parent()->find_block(block); + } +} + /////////////////// // FileEnv /////////////////// @@ -179,7 +201,17 @@ void FunctionEnv::emit(std::unique_ptr ir) { m_code.push_back(std::move(ir)); } void FunctionEnv::finish() { - // todo resolve gotos + resolve_gotos(); +} + +void FunctionEnv::resolve_gotos() { + for (auto& gt : unresolved_gotos) { + auto kv_label = m_labels.find(gt.label); + if (kv_label == m_labels.end()) { + throw std::runtime_error("Invalid goto " + gt.label); + } + gt.ir->resolve(&kv_label->second); + } } RegVal* FunctionEnv::make_ireg(TypeSpec ts, emitter::RegKind kind) { @@ -189,4 +221,12 @@ RegVal* FunctionEnv::make_ireg(TypeSpec ts, emitter::RegKind kind) { auto rv = std::make_unique(ireg, ts); m_iregs.push_back(std::move(rv)); return m_iregs.back().get(); +} + +std::unordered_map& FunctionEnv::get_label_map() { + return m_labels; +} + +std::unordered_map& LabelEnv::get_label_map() { + return m_labels; } \ No newline at end of file diff --git a/goalc/compiler/Env.h b/goalc/compiler/Env.h index c81671c6e..9837ac15f 100644 --- a/goalc/compiler/Env.h +++ b/goalc/compiler/Env.h @@ -33,6 +33,7 @@ class Env { virtual void constrain_reg(IRegConstraint constraint); virtual Val* lexical_lookup(goos::Object sym); virtual BlockEnv* find_block(const std::string& name); + virtual std::unordered_map& get_label_map(); RegVal* make_gpr(TypeSpec ts); RegVal* make_xmm(TypeSpec ts); virtual ~Env() = default; @@ -117,10 +118,18 @@ class DeclareEnv : public Env { } settings; }; +class IR_GotoLabel; + +struct UnresolvedGoto { + IR_GotoLabel* ir; + std::string label; +}; + class FunctionEnv : public DeclareEnv { public: FunctionEnv(Env* parent, std::string name); std::string print() override; + std::unordered_map& get_label_map() override; void set_segment(int seg) { segment = seg; } void emit(std::unique_ptr ir) override; void finish(); @@ -140,14 +149,26 @@ class FunctionEnv : public DeclareEnv { m_vals.push_back(std::move(new_obj)); return (T*)m_vals.back().get(); } + + template + T* alloc_env(Args&&... args) { + std::unique_ptr new_obj = std::make_unique(std::forward(args)...); + m_envs.push_back(std::move(new_obj)); + return (T*)m_envs.back().get(); + } + int segment = -1; std::string method_of_type_name = "#f"; + std::vector unresolved_gotos; + protected: + void resolve_gotos(); std::string m_name; std::vector> m_code; std::vector> m_iregs; std::vector> m_vals; + std::vector> m_envs; std::vector m_constraints; // todo, unresolved gotos AllocationResult m_regalloc_result; @@ -156,6 +177,7 @@ class FunctionEnv : public DeclareEnv { bool m_aligned_stack_required = false; std::unordered_map m_params; + std::unordered_map m_labels; }; class BlockEnv : public Env { @@ -164,11 +186,10 @@ class BlockEnv : public Env { std::string print() override; BlockEnv* find_block(const std::string& name) override; - protected: - std::string m_name; - Label* m_end_label = nullptr; - Val* m_return_value = nullptr; - std::vector m_return_types; + std::string name; + Label end_label = nullptr; + RegVal* return_value = nullptr; + std::vector return_types; }; class LexicalEnv : public Env { @@ -179,6 +200,8 @@ class LexicalEnv : public Env { class LabelEnv : public Env { public: + std::unordered_map& get_label_map() override; + protected: std::unordered_map m_labels; }; diff --git a/goalc/compiler/IR.cpp b/goalc/compiler/IR.cpp index 33afba90b..236662ba1 100644 --- a/goalc/compiler/IR.cpp +++ b/goalc/compiler/IR.cpp @@ -168,4 +168,75 @@ void IR_GetSymbolValue::do_codegen(emitter::ObjectGenerator* gen, irec); gen->link_instruction_symbol_mem(instr, m_src->name()); } +} + +///////////////////// +// RegSet +///////////////////// + +IR_RegSet::IR_RegSet(const RegVal* dest, const RegVal* src) : m_dest(dest), m_src(src) {} + +RegAllocInstr IR_RegSet::to_rai() { + RegAllocInstr rai; + rai.write.push_back(m_dest->ireg()); + rai.read.push_back(m_src->ireg()); + if (m_dest->ireg().kind == m_src->ireg().kind) { + rai.is_move = true; // only true if we aren't moving from register kind to register kind + } + return rai; +} + +void IR_RegSet::do_codegen(emitter::ObjectGenerator* gen, + const AllocationResult& allocs, + emitter::IR_Record irec) { + auto val_reg = get_reg(m_src, allocs, irec); + auto dest_reg = get_reg(m_dest, allocs, irec); + + if (val_reg == dest_reg) { + gen->add_instr(IGen::null(), irec); + } else { + gen->add_instr(IGen::mov_gpr64_gpr64(dest_reg, val_reg), irec); + } +} + +std::string IR_RegSet::print() { + return fmt::format("mov {}, {}", m_dest->print(), m_src->print()); +} + +///////////////////// +// GotoLabel +///////////////////// + +IR_GotoLabel::IR_GotoLabel(const Label* dest) : m_dest(dest) { + m_resolved = true; +} + +IR_GotoLabel::IR_GotoLabel() { + m_resolved = false; +} + +std::string IR_GotoLabel::print() { + return fmt::format("goto {}", m_dest->print()); +} + +RegAllocInstr IR_GotoLabel::to_rai() { + assert(m_resolved); + RegAllocInstr rai; + rai.jumps.push_back(m_dest->idx); + rai.fallthrough = false; + return rai; +} + +void IR_GotoLabel::do_codegen(emitter::ObjectGenerator* gen, + const AllocationResult& allocs, + emitter::IR_Record irec) { + (void)allocs; + auto instr = gen->add_instr(IGen::jmp_32(), irec); + gen->link_instruction_jump(instr, gen->get_future_ir_record_in_same_func(irec, m_dest->idx)); +} + +void IR_GotoLabel::resolve(const Label* dest) { + assert(!m_resolved); + m_dest = dest; + m_resolved = true; } \ No newline at end of file diff --git a/goalc/compiler/IR.h b/goalc/compiler/IR.h index b06845e0b..65e374742 100644 --- a/goalc/compiler/IR.h +++ b/goalc/compiler/IR.h @@ -99,4 +99,34 @@ class IR_GetSymbolValue : public IR { bool m_sext = false; }; +class IR_RegSet : public IR { + public: + IR_RegSet(const RegVal* dest, const RegVal* src); + std::string print() override; + RegAllocInstr to_rai() override; + void do_codegen(emitter::ObjectGenerator* gen, + const AllocationResult& allocs, + emitter::IR_Record irec) override; + + protected: + const RegVal* m_dest = nullptr; + const RegVal* m_src = nullptr; +}; + +class IR_GotoLabel : public IR { + public: + IR_GotoLabel(); + void resolve(const Label* dest); + explicit IR_GotoLabel(const Label* dest); + std::string print() override; + RegAllocInstr to_rai() override; + void do_codegen(emitter::ObjectGenerator* gen, + const AllocationResult& allocs, + emitter::IR_Record irec) override; + + protected: + const Label* m_dest = nullptr; + bool m_resolved = false; +}; + #endif // JAK_IR_H diff --git a/goalc/compiler/Label.h b/goalc/compiler/Label.h index 0307a723f..61336994a 100644 --- a/goalc/compiler/Label.h +++ b/goalc/compiler/Label.h @@ -1,8 +1,13 @@ - - #ifndef JAK_LABEL_H #define JAK_LABEL_H -struct Label {}; +class FunctionEnv; +struct Label { + Label() = default; + Label(FunctionEnv* f, int _idx = -1) : func(f), idx(_idx) {} + FunctionEnv* func = nullptr; + int idx = -1; + std::string print() const { return "label-" + std::to_string(idx); } +}; #endif // JAK_LABEL_H diff --git a/goalc/compiler/Util.cpp b/goalc/compiler/Util.cpp index 435055de1..c891c5be2 100644 --- a/goalc/compiler/Util.cpp +++ b/goalc/compiler/Util.cpp @@ -103,4 +103,18 @@ std::string Compiler::as_string(const goos::Object& o) { std::string Compiler::symbol_string(const goos::Object& o) { return o.as_symbol()->name; +} + +const goos::Object& Compiler::pair_car(const goos::Object& o) { + return o.as_pair()->car; +} + +const goos::Object& Compiler::pair_cdr(const goos::Object& o) { + return o.as_pair()->cdr; +} + +void Compiler::expect_empty_list(const goos::Object& o) { + if (!o.is_empty_list()) { + throw_compile_error(o, "expected to be an empty list"); + } } \ No newline at end of file diff --git a/goalc/compiler/compilation/Atoms.cpp b/goalc/compiler/compilation/Atoms.cpp index aa66b84e2..9f3be74ce 100644 --- a/goalc/compiler/compilation/Atoms.cpp +++ b/goalc/compiler/compilation/Atoms.cpp @@ -19,10 +19,10 @@ static const std::unordered_map< // // BLOCK FORMS {"top-level", &Compiler::compile_top_level}, {"begin", &Compiler::compile_begin}, - // {"block", &Compiler::compile_block}, - // {"return-from", &Compiler::compile_return_from}, - // {"label", &Compiler::compile_label}, - // {"goto", &Compiler::compile_goto}, + {"block", &Compiler::compile_block}, + {"return-from", &Compiler::compile_return_from}, + {"label", &Compiler::compile_label}, + {"goto", &Compiler::compile_goto}, // // // COMPILER CONTROL // {"gs", &Compiler::compile_gs}, @@ -36,7 +36,7 @@ static const std::unordered_map< // // // CONDITIONAL COMPILATION {"#cond", &Compiler::compile_gscond}, - // {"defglobalconstant", &Compiler::compile_defglobalconstant}, + {"defglobalconstant", &Compiler::compile_defglobalconstant}, {"seval", &Compiler::compile_seval}, // // // CONTROL FLOW @@ -200,6 +200,21 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) { // todo lexical // todo global constant + auto global_constant = m_global_constants.find(form.as_symbol()); + auto existing_symbol = m_symbol_types.find(form.as_symbol()->name); + + if (global_constant != m_global_constants.end()) { + // check there is no symbol with the same name + if (existing_symbol != m_symbol_types.end()) { + throw_compile_error(form, + "symbol is both a runtime symbol and a global constant. Something is " + "likely very wrong."); + } + + // got a global constant + return compile_error_guard(global_constant->second, env); + } + return compile_get_symbol_value(name, env); } diff --git a/goalc/compiler/compilation/Block.cpp b/goalc/compiler/compilation/Block.cpp index 404d022f7..1db698041 100644 --- a/goalc/compiler/compilation/Block.cpp +++ b/goalc/compiler/compilation/Block.cpp @@ -13,3 +13,132 @@ Val* Compiler::compile_begin(const goos::Object& form, const goos::Object& rest, for_each_in_list(rest, [&](const Object& o) { result = compile_error_guard(o, env); }); return result; } + +Val* Compiler::compile_block(const goos::Object& form, const goos::Object& _rest, Env* env) { + auto rest = &_rest; + auto name = pair_car(*rest); + rest = &pair_cdr(*rest); + + if (!rest->is_pair()) { + throw_compile_error(form, "Block form has an empty or invliad body"); + } + + auto fe = get_parent_env_of_type(env); + + // create environment + auto block_env = fe->alloc_env(env, symbol_string(name)); + + // we need to create a return value register, as a "return-from" statement inside the block may + // set it. for now it has a type of none, but we will set it more accurate after compiling the + // block. + // block_env->return_value = env->alloc_reg(get_base_typespec("none")); + block_env->return_value = env->make_gpr(m_ts.make_typespec("none")); + + // create label to the end of the block (we don't yet know where it is...) + block_env->end_label = Label(fe); + + // compile everything in the body + Val* result = get_none(); + for_each_in_list(*rest, [&](const Object& o) { result = compile_error_guard(o, block_env); }); + + // if no return-from's were used, we can ignore the return_value register, and basically turn this + // into a begin. this allows a block which returns a floating point value to return the value in + // an xmm register, which is likely to eliminate a gpr->xmm move. + if (block_env->return_types.empty()) { + return result; + } + + // determine return type as the lowest common ancestor of the block's last form and any + // return-from's + auto& return_types = block_env->return_types; + return_types.push_back(result->type()); + auto return_type = m_ts.lowest_common_ancestor(return_types); + block_env->return_value->set_type(return_type); + + // an IR to move the result of the block into the block's return register (if no return-from's are + // taken) + auto ir_move_rv = std::make_unique(block_env->return_value, result->to_gpr(fe)); + + // note - one drawback of doing this single pass is that a block always evaluates to a gpr. + // so we may have an unneeded xmm -> gpr move that could have been an xmm -> xmm that could have + // been eliminated. + env->emit(std::move(ir_move_rv)); + + // now we know the end of the block, so we set the label index to be on whatever comes after the + // return move. functions always end with a "null" IR and "null" instruction, so this is safe. + block_env->end_label.idx = block_env->end_label.func->code().size(); + + return block_env->return_value; +} + +Val* Compiler::compile_return_from(const goos::Object& form, const goos::Object& _rest, Env* env) { + const Object* rest = &_rest; + auto block_name = symbol_string(pair_car(*rest)); + rest = &pair_cdr(*rest); + auto value_expression = pair_car(*rest); + expect_empty_list(pair_cdr(*rest)); + + // evaluate expression to return + auto result = compile_error_guard(value_expression, env); + auto fe = get_parent_env_of_type(env); + + // find block to return from + auto block = dynamic_cast(env->find_block(block_name)); + if (!block) { + throw_compile_error(form, + "The return-from form was unable to find a block named " + block_name); + } + + // move result into return register + auto ir_move_rv = std::make_unique(block->return_value, result->to_gpr(fe)); + + // inform block of our possible return type + block->return_types.push_back(result->type()); + + env->emit(std::move(ir_move_rv)); + + // jump to end of block + auto ir_jump = std::make_unique(&block->end_label); + // we know this label is a real label. even though end_label doesn't know where it is, there is an + // actual label object. this means we won't try to resolve this label _by name_ later on when the + // block is done. + // ir_jump->resolved = true; + env->emit(std::move(ir_jump)); + + // In the real GOAL, there is likely a bug here where a non-none value is returned. + return get_none(); +} + +Val* Compiler::compile_label(const goos::Object& form, const goos::Object& rest, Env* env) { + auto label_name = symbol_string(pair_car(rest)); + expect_empty_list(pair_cdr(rest)); + + // make sure we don't have a label with this name already + auto& labels = env->get_label_map(); + auto kv = labels.find(label_name); + if (kv != labels.end()) { + throw_compile_error( + form, "There are two labels named " + label_name + " in the same label environment"); + } + + // make a label pointing to the end of the current function env. + auto func_env = get_parent_env_of_type(env); + labels[label_name] = Label(func_env, func_env->code().size()); + return get_none(); +} + +Val* Compiler::compile_goto(const goos::Object& form, const goos::Object& rest, Env* env) { + (void)form; + auto label_name = symbol_string(pair_car(rest)); + expect_empty_list(pair_cdr(rest)); + + auto ir_goto = std::make_unique(); + // this requires looking up the label by name after, as it may be a goto to a label which has not + // yet been defined. + + // 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->emit(std::move(ir_goto)); + return get_none(); +} \ No newline at end of file diff --git a/goalc/compiler/compilation/Macro.cpp b/goalc/compiler/compilation/Macro.cpp index a5d6b6aa2..89b5afb26 100644 --- a/goalc/compiler/compilation/Macro.cpp +++ b/goalc/compiler/compilation/Macro.cpp @@ -28,6 +28,7 @@ Val* Compiler::compile_goos_macro(const goos::Object& o, 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(); 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; @@ -85,5 +86,32 @@ Val* Compiler::compile_quote(const goos::Object& form, const goos::Object& rest, default: throw_compile_error(form, "Can't quote this"); } + return get_none(); +} + +Val* Compiler::compile_defglobalconstant(const goos::Object& form, + const goos::Object& _rest, + Env* env) { + auto rest = &_rest; + (void)env; + if (!rest->is_pair()) { + throw_compile_error(form, "invalid defglobalconstant"); + } + + auto sym = pair_car(*rest).as_symbol(); + rest = &pair_cdr(*rest); + auto value = pair_car(*rest); + + rest = &rest->as_pair()->cdr; + if (!rest->is_empty_list()) { + throw_compile_error(form, "invalid defglobalconstant"); + } + + // GOAL constant + m_global_constants[sym] = value; + + // GOOS constant + m_goos.global_environment.as_env()->vars[sym] = value; + return get_none(); } \ No newline at end of file diff --git a/goalc/emitter/ObjectGenerator.cpp b/goalc/emitter/ObjectGenerator.cpp index 1f9da2921..0c14eb1e3 100644 --- a/goalc/emitter/ObjectGenerator.cpp +++ b/goalc/emitter/ObjectGenerator.cpp @@ -136,6 +136,15 @@ IR_Record ObjectGenerator::get_future_ir_record(const FunctionRecord& func, int return rec; } +IR_Record ObjectGenerator::get_future_ir_record_in_same_func(const IR_Record& irec, int ir_id) { + assert(irec.func_id == int(m_function_data_by_seg.at(irec.seg).size()) - 1); + IR_Record rec; + rec.seg = irec.seg; + rec.func_id = irec.func_id; + rec.ir_id = ir_id; + return rec; +} + /*! * Add a new Instruction for the given IR instruction. */ diff --git a/goalc/emitter/ObjectGenerator.h b/goalc/emitter/ObjectGenerator.h index 968577cbc..4d3c436c1 100644 --- a/goalc/emitter/ObjectGenerator.h +++ b/goalc/emitter/ObjectGenerator.h @@ -43,6 +43,7 @@ class ObjectGenerator { int min_align = 16); // should align and insert function tag IR_Record add_ir(const FunctionRecord& func); IR_Record get_future_ir_record(const FunctionRecord& func, int ir_id); + IR_Record get_future_ir_record_in_same_func(const IR_Record& irec, int ir_id); InstructionRecord add_instr(Instruction inst, IR_Record ir); void add_instr_no_ir(FunctionRecord func, Instruction inst); StaticRecord add_static_to_seg(int seg, int min_align = 16); diff --git a/test/test_compiler_and_runtime.cpp b/test/test_compiler_and_runtime.cpp index fffb74b45..8192b3a46 100644 --- a/test/test_compiler_and_runtime.cpp +++ b/test/test_compiler_and_runtime.cpp @@ -111,6 +111,12 @@ TEST(CompilerAndRuntime, CompilerTests) { runner.run_test("test-get-symbol-1.gc", {"1342756\n"}); // 0x147d24 in hex runner.run_test("test-get-symbol-2.gc", {"1342764\n"}); // 0x147d2c in hex runner.run_test("test-define-1.gc", {"17\n"}); + runner.run_test("test-nested-blocks-1.gc", {"7\n"}); + runner.run_test("test-nested-blocks-2.gc", {"8\n"}); + runner.run_test("test-nested-blocks-3.gc", {"7\n"}); + runner.run_test("test-goto-1.gc", {"3\n"}); + runner.run_test("test-defglobalconstant-1.gc", {"17\n"}); + runner.run_test("test-defglobalconstant-2.gc", {"18\n"}); compiler.shutdown_target(); runtime_thread.join();