mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
17 of 124 compiler tests passing
This commit is contained in:
parent
ee4eb9f128
commit
1394cf13cd
|
@ -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<Function> 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__
|
||||
|
|
5
goal_src/test/test-defglobalconstant-1.gc
Normal file
5
goal_src/test/test-defglobalconstant-1.gc
Normal file
|
@ -0,0 +1,5 @@
|
|||
(defglobalconstant my-constant 12)
|
||||
(defglobalconstant my-constant 17)
|
||||
(defglobalconstant not-my-consant 13)
|
||||
|
||||
my-constant
|
8
goal_src/test/test-defglobalconstant-2.gc
Normal file
8
goal_src/test/test-defglobalconstant-2.gc
Normal file
|
@ -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)
|
9
goal_src/test/test-goto-1.gc
Normal file
9
goal_src/test/test-goto-1.gc
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
|
||||
(block my-block
|
||||
1
|
||||
(goto skip-early-return)
|
||||
(return-from my-block 2)
|
||||
(label skip-early-return)
|
||||
3
|
||||
)
|
11
goal_src/test/test-nested-blocks-1.gc
Normal file
11
goal_src/test/test-nested-blocks-1.gc
Normal file
|
@ -0,0 +1,11 @@
|
|||
(block outer-block
|
||||
1
|
||||
2
|
||||
(block inner-block
|
||||
3
|
||||
4
|
||||
(return-from inner-block 7)
|
||||
5
|
||||
6
|
||||
)
|
||||
)
|
11
goal_src/test/test-nested-blocks-2.gc
Normal file
11
goal_src/test/test-nested-blocks-2.gc
Normal file
|
@ -0,0 +1,11 @@
|
|||
(block outer-block
|
||||
1
|
||||
2
|
||||
(block inner-block
|
||||
3
|
||||
4
|
||||
(return-from inner-block 7)
|
||||
5
|
||||
)
|
||||
8
|
||||
)
|
11
goal_src/test/test-nested-blocks-3.gc
Normal file
11
goal_src/test/test-nested-blocks-3.gc
Normal file
|
@ -0,0 +1,11 @@
|
|||
(block outer-block
|
||||
1
|
||||
2
|
||||
(block inner-block
|
||||
3
|
||||
4
|
||||
(return-from outer-block 7)
|
||||
5
|
||||
)
|
||||
8
|
||||
)
|
|
@ -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);
|
||||
}
|
|
@ -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<GlobalEnv> 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
|
||||
|
|
|
@ -47,6 +47,10 @@ RegVal* Env::make_xmm(TypeSpec ts) {
|
|||
return make_ireg(std::move(ts), emitter::RegKind::XMM);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, Label>& Env::get_label_map() {
|
||||
return parent()->get_label_map();
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// GlobalEnv
|
||||
///////////////////
|
||||
|
@ -123,6 +127,24 @@ void NoEmitEnv::emit(std::unique_ptr<IR> 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> 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<RegVal>(ireg, ts);
|
||||
m_iregs.push_back(std::move(rv));
|
||||
return m_iregs.back().get();
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, Label>& FunctionEnv::get_label_map() {
|
||||
return m_labels;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, Label>& LabelEnv::get_label_map() {
|
||||
return m_labels;
|
||||
}
|
|
@ -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<std::string, Label>& 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<std::string, Label>& get_label_map() override;
|
||||
void set_segment(int seg) { segment = seg; }
|
||||
void emit(std::unique_ptr<IR> 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 <typename T, class... Args>
|
||||
T* alloc_env(Args&&... args) {
|
||||
std::unique_ptr<T> new_obj = std::make_unique<T>(std::forward<Args>(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<UnresolvedGoto> unresolved_gotos;
|
||||
|
||||
protected:
|
||||
void resolve_gotos();
|
||||
std::string m_name;
|
||||
std::vector<std::unique_ptr<IR>> m_code;
|
||||
std::vector<std::unique_ptr<RegVal>> m_iregs;
|
||||
std::vector<std::unique_ptr<Val>> m_vals;
|
||||
std::vector<std::unique_ptr<Env>> m_envs;
|
||||
std::vector<IRegConstraint> 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<std::string, Env*> m_params;
|
||||
std::unordered_map<std::string, Label> 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<TypeSpec> m_return_types;
|
||||
std::string name;
|
||||
Label end_label = nullptr;
|
||||
RegVal* return_value = nullptr;
|
||||
std::vector<TypeSpec> return_types;
|
||||
};
|
||||
|
||||
class LexicalEnv : public Env {
|
||||
|
@ -179,6 +200,8 @@ class LexicalEnv : public Env {
|
|||
|
||||
class LabelEnv : public Env {
|
||||
public:
|
||||
std::unordered_map<std::string, Label>& get_label_map() override;
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, Label> m_labels;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<FunctionEnv>(env);
|
||||
|
||||
// create environment
|
||||
auto block_env = fe->alloc_env<BlockEnv>(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<IR_RegSet>(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<FunctionEnv>(env);
|
||||
|
||||
// find block to return from
|
||||
auto block = dynamic_cast<BlockEnv*>(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<IR_RegSet>(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<IR_GotoLabel>(&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<FunctionEnv>(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<IR_GotoLabel>();
|
||||
// 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<FunctionEnv>(env)->unresolved_gotos.push_back({ir_goto.get(), label_name});
|
||||
env->emit(std::move(ir_goto));
|
||||
return get_none();
|
||||
}
|
|
@ -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<FunctionEnv>(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();
|
||||
}
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue