Register booleans as internal types.
This commit is contained in:
parent
df5f5eba1c
commit
73441dc93b
|
@ -204,10 +204,10 @@ type_ptr ast_case::typecheck(type_mgr& mgr, type_env_ptr& env) {
|
||||||
|
|
||||||
input_type = mgr.resolve(case_type, var);
|
input_type = mgr.resolve(case_type, var);
|
||||||
type_app* app_type;
|
type_app* app_type;
|
||||||
if(!(app_type = dynamic_cast<type_app*>(input_type.get())) ||
|
// if(!(app_type = dynamic_cast<type_app*>(input_type.get())) ||
|
||||||
!dynamic_cast<type_data*>(app_type->constructor.get())) {
|
// !dynamic_cast<type_data*>(app_type->constructor.get())) {
|
||||||
throw type_error("attempting case analysis of non-data type", of->loc);
|
// throw type_error("attempting case analysis of non-data type", of->loc);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return branch_type;
|
return branch_type;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +251,11 @@ struct case_mappings {
|
||||||
return *default_case;
|
return *default_case;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<instruction_ptr>& get_case_for(tag_type tag) {
|
||||||
|
if(case_defined_for(tag)) return get_specific_case_for(tag);
|
||||||
|
return get_default_case();
|
||||||
|
}
|
||||||
|
|
||||||
bool case_defined_for(tag_type tag) {
|
bool case_defined_for(tag_type tag) {
|
||||||
return defined_cases.find(tag) != defined_cases.end();
|
return defined_cases.find(tag) != defined_cases.end();
|
||||||
}
|
}
|
||||||
|
@ -288,8 +293,19 @@ struct case_strategy_bool {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
instruction_ptr into_instruction(const type* type, case_mappings<case_strategy_bool>& ms) {
|
void into_instructions(
|
||||||
throw std::runtime_error("boolean case unimplemented!");
|
const type* type,
|
||||||
|
case_mappings<case_strategy_bool>& ms,
|
||||||
|
std::vector<instruction_ptr>& into) {
|
||||||
|
if(ms.defined_cases_count() == 0) {
|
||||||
|
for(auto& instruction : ms.get_default_case())
|
||||||
|
into.push_back(std::move(instruction));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
into.push_back(instruction_ptr(new instruction_if(
|
||||||
|
std::move(ms.get_case_for(true)),
|
||||||
|
std::move(ms.get_case_for(false)))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -327,7 +343,10 @@ struct case_strategy_data {
|
||||||
return static_cast<const type_data*>(type)->constructors.size();
|
return static_cast<const type_data*>(type)->constructors.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
instruction_ptr into_instruction(const type* type, case_mappings<case_strategy_data>& ms) {
|
void into_instructions(
|
||||||
|
const type* type,
|
||||||
|
case_mappings<case_strategy_data>& ms,
|
||||||
|
std::vector<instruction_ptr>& into) {
|
||||||
instruction_jump* jump_instruction = new instruction_jump();
|
instruction_jump* jump_instruction = new instruction_jump();
|
||||||
instruction_ptr inst(jump_instruction);
|
instruction_ptr inst(jump_instruction);
|
||||||
|
|
||||||
|
@ -350,7 +369,7 @@ struct case_strategy_data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::move(inst);
|
into.push_back(std::move(inst));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -364,6 +383,7 @@ void compile_case(const ast_case& node, const env_ptr& env, const type* type, st
|
||||||
auto& branch_into = cases.make_default_case();
|
auto& branch_into = cases.make_default_case();
|
||||||
env_ptr new_env(new env_var(branch->expr->env->get_mangled_name(vpat->var), env));
|
env_ptr new_env(new env_var(branch->expr->env->get_mangled_name(vpat->var), env));
|
||||||
branch->expr->compile(new_env, branch_into);
|
branch->expr->compile(new_env, branch_into);
|
||||||
|
branch_into.push_back(instruction_ptr(new instruction_slide(1)));
|
||||||
} else {
|
} else {
|
||||||
auto repr = strategy.from_typed_pattern(branch->pat, type);
|
auto repr = strategy.from_typed_pattern(branch->pat, type);
|
||||||
auto& branch_into = cases.make_case_for(strategy.tag_from_repr(repr));
|
auto& branch_into = cases.make_case_for(strategy.tag_from_repr(repr));
|
||||||
|
@ -375,7 +395,7 @@ void compile_case(const ast_case& node, const env_ptr& env, const type* type, st
|
||||||
cases.default_case_defined()))
|
cases.default_case_defined()))
|
||||||
throw type_error("incomplete patterns", node.loc);
|
throw type_error("incomplete patterns", node.loc);
|
||||||
|
|
||||||
into.push_back(strategy.into_instruction(type, cases));
|
strategy.into_instructions(type, cases, into);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_case::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
void ast_case::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||||
|
|
|
@ -122,6 +122,45 @@ void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||||
ctx.builder.SetInsertPoint(safety_block);
|
ctx.builder.SetInsertPoint(safety_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void instruction_if::print(int indent, std::ostream& to) const {
|
||||||
|
print_indent(indent, to);
|
||||||
|
to << "If(" << std::endl;
|
||||||
|
for(auto& instruction : on_true) {
|
||||||
|
instruction->print(indent + 2, to);
|
||||||
|
}
|
||||||
|
to << std::endl;
|
||||||
|
for(auto& instruction : on_false) {
|
||||||
|
instruction->print(indent + 2, to);
|
||||||
|
}
|
||||||
|
print_indent(indent, to);
|
||||||
|
to << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void instruction_if::gen_llvm(llvm_context& ctx, llvm::Function* f) const {
|
||||||
|
auto top_node = ctx.create_peek(f, ctx.create_size(0));
|
||||||
|
auto num = ctx.unwrap_num(top_node);
|
||||||
|
|
||||||
|
auto nonzero_block = BasicBlock::Create(ctx.ctx, "nonzero", f);
|
||||||
|
auto zero_block = BasicBlock::Create(ctx.ctx, "zero", f);
|
||||||
|
auto resume_block = BasicBlock::Create(ctx.ctx, "resume", f);
|
||||||
|
auto switch_op = ctx.builder.CreateSwitch(num, nonzero_block, 2);
|
||||||
|
|
||||||
|
switch_op->addCase(ctx.create_i32(0), zero_block);
|
||||||
|
ctx.builder.SetInsertPoint(nonzero_block);
|
||||||
|
for(auto& instruction : on_true) {
|
||||||
|
instruction->gen_llvm(ctx, f);
|
||||||
|
}
|
||||||
|
ctx.builder.CreateBr(resume_block);
|
||||||
|
|
||||||
|
ctx.builder.SetInsertPoint(zero_block);
|
||||||
|
for(auto& instruction : on_true) {
|
||||||
|
instruction->gen_llvm(ctx, f);
|
||||||
|
}
|
||||||
|
ctx.builder.CreateBr(resume_block);
|
||||||
|
|
||||||
|
ctx.builder.SetInsertPoint(resume_block);
|
||||||
|
}
|
||||||
|
|
||||||
void instruction_slide::print(int indent, std::ostream& to) const {
|
void instruction_slide::print(int indent, std::ostream& to) const {
|
||||||
print_indent(indent, to);
|
print_indent(indent, to);
|
||||||
to << "Slide(" << offset << ")" << std::endl;
|
to << "Slide(" << offset << ")" << std::endl;
|
||||||
|
|
|
@ -101,6 +101,19 @@ struct instruction_jump : public instruction {
|
||||||
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
|
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct instruction_if : public instruction {
|
||||||
|
std::vector<instruction_ptr> on_true;
|
||||||
|
std::vector<instruction_ptr> on_false;
|
||||||
|
|
||||||
|
instruction_if(
|
||||||
|
std::vector<instruction_ptr> t,
|
||||||
|
std::vector<instruction_ptr> f)
|
||||||
|
: on_true(std::move(t)), on_false(std::move(f)) {}
|
||||||
|
|
||||||
|
void print(int indent, std::ostream& to) const;
|
||||||
|
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct instruction_slide : public instruction {
|
struct instruction_slide : public instruction {
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,15 @@ void yy::parser::error(const yy::location& loc, const std::string& msg) {
|
||||||
std::cout << "An error occured: " << msg << std::endl;
|
std::cout << "An error occured: " << msg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void typecheck_program(
|
void prelude_types(definition_group& defs, type_env_ptr env) {
|
||||||
definition_group& defs,
|
|
||||||
type_mgr& mgr, type_env_ptr& env) {
|
|
||||||
type_ptr int_type = type_ptr(new type_internal("Int"));
|
type_ptr int_type = type_ptr(new type_internal("Int"));
|
||||||
env->bind_type("Int", int_type);
|
env->bind_type("Int", int_type);
|
||||||
type_ptr int_type_app = type_ptr(new type_app(int_type));
|
type_ptr int_type_app = type_ptr(new type_app(int_type));
|
||||||
|
|
||||||
|
type_ptr bool_type = type_ptr(new type_internal("Bool"));
|
||||||
|
env->bind_type("Bool", bool_type);
|
||||||
|
type_ptr bool_type_app = type_ptr(new type_app(bool_type));
|
||||||
|
|
||||||
type_ptr binop_type = type_ptr(new type_arr(
|
type_ptr binop_type = type_ptr(new type_arr(
|
||||||
int_type_app,
|
int_type_app,
|
||||||
type_ptr(new type_arr(int_type_app, int_type_app))));
|
type_ptr(new type_arr(int_type_app, int_type_app))));
|
||||||
|
@ -37,6 +39,15 @@ void typecheck_program(
|
||||||
env->bind("*", binop_type, visibility::global);
|
env->bind("*", binop_type, visibility::global);
|
||||||
env->bind("/", binop_type, visibility::global);
|
env->bind("/", binop_type, visibility::global);
|
||||||
|
|
||||||
|
env->bind("True", bool_type_app, visibility::global);
|
||||||
|
env->bind("False", bool_type_app, visibility::global);
|
||||||
|
}
|
||||||
|
|
||||||
|
void typecheck_program(
|
||||||
|
definition_group& defs,
|
||||||
|
type_mgr& mgr, type_env_ptr& env) {
|
||||||
|
prelude_types(defs, env);
|
||||||
|
|
||||||
std::set<std::string> free;
|
std::set<std::string> free;
|
||||||
defs.find_free(free);
|
defs.find_free(free);
|
||||||
defs.typecheck(mgr, env);
|
defs.typecheck(mgr, env);
|
||||||
|
@ -60,23 +71,6 @@ global_scope translate_program(definition_group& group) {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gen_llvm_internal_op(llvm_context& ctx, binop op) {
|
|
||||||
auto new_function = ctx.create_custom_function(op_action(op), 2);
|
|
||||||
std::vector<instruction_ptr> instructions;
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_push(1)));
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_eval()));
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_push(1)));
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_eval()));
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_binop(op)));
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_update(2)));
|
|
||||||
instructions.push_back(instruction_ptr(new instruction_pop(2)));
|
|
||||||
ctx.builder.SetInsertPoint(&new_function->getEntryBlock());
|
|
||||||
for(auto& instruction : instructions) {
|
|
||||||
instruction->gen_llvm(ctx, new_function);
|
|
||||||
}
|
|
||||||
ctx.builder.CreateRetVoid();
|
|
||||||
}
|
|
||||||
|
|
||||||
void output_llvm(llvm_context& ctx, const std::string& filename) {
|
void output_llvm(llvm_context& ctx, const std::string& filename) {
|
||||||
std::string targetTriple = llvm::sys::getDefaultTargetTriple();
|
std::string targetTriple = llvm::sys::getDefaultTargetTriple();
|
||||||
|
|
||||||
|
@ -117,12 +111,43 @@ void output_llvm(llvm_context& ctx, const std::string& filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gen_llvm_internal_op(llvm_context& ctx, binop op) {
|
||||||
|
auto new_function = ctx.create_custom_function(op_action(op), 2);
|
||||||
|
std::vector<instruction_ptr> instructions;
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_push(1)));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_eval()));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_push(1)));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_eval()));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_binop(op)));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_update(2)));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_pop(2)));
|
||||||
|
ctx.builder.SetInsertPoint(&new_function->getEntryBlock());
|
||||||
|
for(auto& instruction : instructions) {
|
||||||
|
instruction->gen_llvm(ctx, new_function);
|
||||||
|
}
|
||||||
|
ctx.builder.CreateRetVoid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void gen_llvm_boolean_constructor(llvm_context& ctx, const std::string& s, bool b) {
|
||||||
|
auto new_function = ctx.create_custom_function(s, 0);
|
||||||
|
std::vector<instruction_ptr> instructions;
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_pushint(b)));
|
||||||
|
instructions.push_back(instruction_ptr(new instruction_update(0)));
|
||||||
|
ctx.builder.SetInsertPoint(&new_function->getEntryBlock());
|
||||||
|
for(auto& instruction : instructions) {
|
||||||
|
instruction->gen_llvm(ctx, new_function);
|
||||||
|
}
|
||||||
|
ctx.builder.CreateRetVoid();
|
||||||
|
}
|
||||||
|
|
||||||
void gen_llvm(global_scope& scope) {
|
void gen_llvm(global_scope& scope) {
|
||||||
llvm_context ctx;
|
llvm_context ctx;
|
||||||
gen_llvm_internal_op(ctx, PLUS);
|
gen_llvm_internal_op(ctx, PLUS);
|
||||||
gen_llvm_internal_op(ctx, MINUS);
|
gen_llvm_internal_op(ctx, MINUS);
|
||||||
gen_llvm_internal_op(ctx, TIMES);
|
gen_llvm_internal_op(ctx, TIMES);
|
||||||
gen_llvm_internal_op(ctx, DIVIDE);
|
gen_llvm_internal_op(ctx, DIVIDE);
|
||||||
|
gen_llvm_boolean_constructor(ctx, "True", true);
|
||||||
|
gen_llvm_boolean_constructor(ctx, "False", false);
|
||||||
|
|
||||||
scope.generate_llvm(ctx);
|
scope.generate_llvm(ctx);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user