Register booleans as internal types.

This commit is contained in:
Danila Fedorin 2020-09-10 00:54:35 -07:00
parent df5f5eba1c
commit 73441dc93b
4 changed files with 126 additions and 29 deletions

View File

@ -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;
} }
@ -250,6 +250,11 @@ struct case_mappings {
assert(default_case); assert(default_case);
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 {

View File

@ -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;

View File

@ -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;

View File

@ -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);