Fork off code for part 11 of compiler series.
This commit is contained in:
parent
2e0318347c
commit
682e0d3e1c
43
11/CMakeLists.txt
Normal file
43
11/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
cmake_minimum_required(VERSION 3.1)
|
||||
project(compiler)
|
||||
|
||||
# Find all the required packages
|
||||
find_package(BISON)
|
||||
find_package(FLEX)
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
|
||||
# Set up the flex and bison targets
|
||||
bison_target(parser
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parser.y
|
||||
${CMAKE_CURRENT_BINARY_DIR}/parser.cpp
|
||||
COMPILE_FLAGS "-d")
|
||||
flex_target(scanner
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scanner.l
|
||||
${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp)
|
||||
add_flex_bison_dependency(scanner parser)
|
||||
|
||||
# Find all the relevant LLVM components
|
||||
llvm_map_components_to_libnames(LLVM_LIBS core x86asmparser x86codegen)
|
||||
|
||||
# Create compiler executable
|
||||
add_executable(compiler
|
||||
ast.cpp ast.hpp definition.cpp
|
||||
llvm_context.cpp llvm_context.hpp
|
||||
type_env.cpp type_env.hpp
|
||||
env.cpp env.hpp
|
||||
type.cpp type.hpp
|
||||
error.cpp error.hpp
|
||||
binop.cpp binop.hpp
|
||||
instruction.cpp instruction.hpp
|
||||
graph.cpp graph.hpp
|
||||
${BISON_parser_OUTPUTS}
|
||||
${FLEX_scanner_OUTPUTS}
|
||||
main.cpp
|
||||
)
|
||||
|
||||
# Configure compiler executable
|
||||
target_include_directories(compiler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(compiler PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_include_directories(compiler PUBLIC ${LLVM_INCLUDE_DIRS})
|
||||
target_compile_definitions(compiler PUBLIC ${LLVM_DEFINITIONS})
|
||||
target_link_libraries(compiler ${LLVM_LIBS})
|
266
11/ast.cpp
Normal file
266
11/ast.cpp
Normal file
|
@ -0,0 +1,266 @@
|
|||
#include "ast.hpp"
|
||||
#include <ostream>
|
||||
#include "binop.hpp"
|
||||
#include "error.hpp"
|
||||
#include "type_env.hpp"
|
||||
|
||||
static void print_indent(int n, std::ostream& to) {
|
||||
while(n--) to << " ";
|
||||
}
|
||||
|
||||
void ast_int::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "INT: " << value << std::endl;
|
||||
}
|
||||
|
||||
void ast_int::find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into) {
|
||||
this->env = env;
|
||||
}
|
||||
|
||||
type_ptr ast_int::typecheck(type_mgr& mgr) {
|
||||
return type_ptr(new type_base("Int"));
|
||||
}
|
||||
|
||||
void ast_int::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||
into.push_back(instruction_ptr(new instruction_pushint(value)));
|
||||
}
|
||||
|
||||
void ast_lid::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "LID: " << id << std::endl;
|
||||
}
|
||||
|
||||
void ast_lid::find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into) {
|
||||
this->env = env;
|
||||
if(env->lookup(id) == nullptr) into.insert(id);
|
||||
}
|
||||
|
||||
type_ptr ast_lid::typecheck(type_mgr& mgr) {
|
||||
return env->lookup(id)->instantiate(mgr);
|
||||
}
|
||||
|
||||
void ast_lid::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||
into.push_back(instruction_ptr(
|
||||
env->has_variable(id) ?
|
||||
(instruction*) new instruction_push(env->get_offset(id)) :
|
||||
(instruction*) new instruction_pushglobal(id)));
|
||||
}
|
||||
|
||||
void ast_uid::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "UID: " << id << std::endl;
|
||||
}
|
||||
|
||||
void ast_uid::find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into) {
|
||||
this->env = env;
|
||||
}
|
||||
|
||||
type_ptr ast_uid::typecheck(type_mgr& mgr) {
|
||||
return env->lookup(id)->instantiate(mgr);
|
||||
}
|
||||
|
||||
void ast_uid::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||
into.push_back(instruction_ptr(new instruction_pushglobal(id)));
|
||||
}
|
||||
|
||||
void ast_binop::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "BINOP: " << op_name(op) << std::endl;
|
||||
left->print(indent + 1, to);
|
||||
right->print(indent + 1, to);
|
||||
}
|
||||
|
||||
void ast_binop::find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into) {
|
||||
this->env = env;
|
||||
left->find_free(mgr, env, into);
|
||||
right->find_free(mgr, env, into);
|
||||
}
|
||||
|
||||
type_ptr ast_binop::typecheck(type_mgr& mgr) {
|
||||
type_ptr ltype = left->typecheck(mgr);
|
||||
type_ptr rtype = right->typecheck(mgr);
|
||||
type_ptr ftype = env->lookup(op_name(op))->instantiate(mgr);
|
||||
if(!ftype) throw type_error(std::string("unknown binary operator ") + op_name(op));
|
||||
|
||||
type_ptr return_type = mgr.new_type();
|
||||
type_ptr arrow_one = type_ptr(new type_arr(rtype, return_type));
|
||||
type_ptr arrow_two = type_ptr(new type_arr(ltype, arrow_one));
|
||||
|
||||
mgr.unify(arrow_two, ftype);
|
||||
return return_type;
|
||||
}
|
||||
|
||||
void ast_binop::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||
right->compile(env, into);
|
||||
left->compile(env_ptr(new env_offset(1, env)), into);
|
||||
|
||||
into.push_back(instruction_ptr(new instruction_pushglobal(op_action(op))));
|
||||
into.push_back(instruction_ptr(new instruction_mkapp()));
|
||||
into.push_back(instruction_ptr(new instruction_mkapp()));
|
||||
}
|
||||
|
||||
void ast_app::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "APP:" << std::endl;
|
||||
left->print(indent + 1, to);
|
||||
right->print(indent + 1, to);
|
||||
}
|
||||
|
||||
void ast_app::find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into) {
|
||||
this->env = env;
|
||||
left->find_free(mgr, env, into);
|
||||
right->find_free(mgr, env, into);
|
||||
}
|
||||
|
||||
type_ptr ast_app::typecheck(type_mgr& mgr) {
|
||||
type_ptr ltype = left->typecheck(mgr);
|
||||
type_ptr rtype = right->typecheck(mgr);
|
||||
|
||||
type_ptr return_type = mgr.new_type();
|
||||
type_ptr arrow = type_ptr(new type_arr(rtype, return_type));
|
||||
mgr.unify(arrow, ltype);
|
||||
return return_type;
|
||||
}
|
||||
|
||||
void ast_app::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||
right->compile(env, into);
|
||||
left->compile(env_ptr(new env_offset(1, env)), into);
|
||||
into.push_back(instruction_ptr(new instruction_mkapp()));
|
||||
}
|
||||
|
||||
void ast_case::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "CASE: " << std::endl;
|
||||
for(auto& branch : branches) {
|
||||
print_indent(indent + 1, to);
|
||||
branch->pat->print(to);
|
||||
to << std::endl;
|
||||
branch->expr->print(indent + 2, to);
|
||||
}
|
||||
}
|
||||
|
||||
void ast_case::find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into) {
|
||||
this->env = env;
|
||||
of->find_free(mgr, env, into);
|
||||
for(auto& branch : branches) {
|
||||
type_env_ptr new_env = type_scope(env);
|
||||
branch->pat->insert_bindings(mgr, new_env);
|
||||
branch->expr->find_free(mgr, new_env, into);
|
||||
}
|
||||
}
|
||||
|
||||
type_ptr ast_case::typecheck(type_mgr& mgr) {
|
||||
type_var* var;
|
||||
type_ptr case_type = mgr.resolve(of->typecheck(mgr), var);
|
||||
type_ptr branch_type = mgr.new_type();
|
||||
|
||||
for(auto& branch : branches) {
|
||||
branch->pat->typecheck(case_type, mgr, branch->expr->env);
|
||||
type_ptr curr_branch_type = branch->expr->typecheck(mgr);
|
||||
mgr.unify(branch_type, curr_branch_type);
|
||||
}
|
||||
|
||||
input_type = mgr.resolve(case_type, var);
|
||||
if(!dynamic_cast<type_data*>(input_type.get())) {
|
||||
throw type_error("attempting case analysis of non-data type");
|
||||
}
|
||||
|
||||
return branch_type;
|
||||
}
|
||||
|
||||
void ast_case::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
|
||||
type_data* type = dynamic_cast<type_data*>(input_type.get());
|
||||
|
||||
of->compile(env, into);
|
||||
into.push_back(instruction_ptr(new instruction_eval()));
|
||||
|
||||
instruction_jump* jump_instruction = new instruction_jump();
|
||||
into.push_back(instruction_ptr(jump_instruction));
|
||||
for(auto& branch : branches) {
|
||||
std::vector<instruction_ptr> branch_instructions;
|
||||
pattern_var* vpat;
|
||||
pattern_constr* cpat;
|
||||
|
||||
if((vpat = dynamic_cast<pattern_var*>(branch->pat.get()))) {
|
||||
branch->expr->compile(env_ptr(new env_offset(1, env)), branch_instructions);
|
||||
|
||||
for(auto& constr_pair : type->constructors) {
|
||||
if(jump_instruction->tag_mappings.find(constr_pair.second.tag) !=
|
||||
jump_instruction->tag_mappings.end())
|
||||
break;
|
||||
|
||||
jump_instruction->tag_mappings[constr_pair.second.tag] =
|
||||
jump_instruction->branches.size();
|
||||
}
|
||||
jump_instruction->branches.push_back(std::move(branch_instructions));
|
||||
} else if((cpat = dynamic_cast<pattern_constr*>(branch->pat.get()))) {
|
||||
env_ptr new_env = env;
|
||||
for(auto it = cpat->params.rbegin(); it != cpat->params.rend(); it++) {
|
||||
new_env = env_ptr(new env_var(*it, new_env));
|
||||
}
|
||||
|
||||
branch_instructions.push_back(instruction_ptr(new instruction_split(
|
||||
cpat->params.size())));
|
||||
branch->expr->compile(new_env, branch_instructions);
|
||||
branch_instructions.push_back(instruction_ptr(new instruction_slide(
|
||||
cpat->params.size())));
|
||||
|
||||
int new_tag = type->constructors[cpat->constr].tag;
|
||||
if(jump_instruction->tag_mappings.find(new_tag) !=
|
||||
jump_instruction->tag_mappings.end())
|
||||
throw type_error("technically not a type error: duplicate pattern");
|
||||
|
||||
jump_instruction->tag_mappings[new_tag] =
|
||||
jump_instruction->branches.size();
|
||||
jump_instruction->branches.push_back(std::move(branch_instructions));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& constr_pair : type->constructors) {
|
||||
if(jump_instruction->tag_mappings.find(constr_pair.second.tag) ==
|
||||
jump_instruction->tag_mappings.end())
|
||||
throw type_error("non-total pattern");
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_var::print(std::ostream& to) const {
|
||||
to << var;
|
||||
}
|
||||
|
||||
void pattern_var::insert_bindings(type_mgr& mgr, type_env_ptr& env) const {
|
||||
env->bind(var, mgr.new_type());
|
||||
}
|
||||
|
||||
void pattern_var::typecheck(type_ptr t, type_mgr& mgr, type_env_ptr& env) const {
|
||||
mgr.unify(env->lookup(var)->instantiate(mgr), t);
|
||||
}
|
||||
|
||||
void pattern_constr::print(std::ostream& to) const {
|
||||
to << constr;
|
||||
for(auto& param : params) {
|
||||
to << " " << param;
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_constr::insert_bindings(type_mgr& mgr, type_env_ptr& env) const {
|
||||
for(auto& param : params) {
|
||||
env->bind(param, mgr.new_type());
|
||||
}
|
||||
}
|
||||
|
||||
void pattern_constr::typecheck(type_ptr t, type_mgr& mgr, type_env_ptr& env) const {
|
||||
type_ptr constructor_type = env->lookup(constr)->instantiate(mgr);
|
||||
if(!constructor_type) {
|
||||
throw type_error(std::string("pattern using unknown constructor ") + constr);
|
||||
}
|
||||
|
||||
for(auto& param : params) {
|
||||
type_arr* arr = dynamic_cast<type_arr*>(constructor_type.get());
|
||||
if(!arr) throw type_error("too many parameters in constructor pattern");
|
||||
|
||||
mgr.unify(env->lookup(param)->instantiate(mgr), arr->left);
|
||||
constructor_type = arr->right;
|
||||
}
|
||||
|
||||
mgr.unify(t, constructor_type);
|
||||
}
|
144
11/ast.hpp
Normal file
144
11/ast.hpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "type.hpp"
|
||||
#include "type_env.hpp"
|
||||
#include "binop.hpp"
|
||||
#include "instruction.hpp"
|
||||
#include "env.hpp"
|
||||
|
||||
struct ast {
|
||||
type_env_ptr env;
|
||||
|
||||
virtual ~ast() = default;
|
||||
|
||||
virtual void print(int indent, std::ostream& to) const = 0;
|
||||
virtual void find_free(type_mgr& mgr,
|
||||
type_env_ptr& env, std::set<std::string>& into) = 0;
|
||||
virtual type_ptr typecheck(type_mgr& mgr) = 0;
|
||||
virtual void compile(const env_ptr& env,
|
||||
std::vector<instruction_ptr>& into) const = 0;
|
||||
};
|
||||
|
||||
using ast_ptr = std::unique_ptr<ast>;
|
||||
|
||||
struct pattern {
|
||||
virtual ~pattern() = default;
|
||||
|
||||
virtual void print(std::ostream& to) const = 0;
|
||||
virtual void insert_bindings(type_mgr& mgr, type_env_ptr& env) const = 0;
|
||||
virtual void typecheck(type_ptr t, type_mgr& mgr, type_env_ptr& env) const = 0;
|
||||
};
|
||||
|
||||
using pattern_ptr = std::unique_ptr<pattern>;
|
||||
|
||||
struct branch {
|
||||
pattern_ptr pat;
|
||||
ast_ptr expr;
|
||||
|
||||
branch(pattern_ptr p, ast_ptr a)
|
||||
: pat(std::move(p)), expr(std::move(a)) {}
|
||||
};
|
||||
|
||||
using branch_ptr = std::unique_ptr<branch>;
|
||||
|
||||
struct ast_int : public ast {
|
||||
int value;
|
||||
|
||||
explicit ast_int(int v)
|
||||
: value(v) {}
|
||||
|
||||
void print(int indent, std::ostream& to) const;
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into);
|
||||
type_ptr typecheck(type_mgr& mgr);
|
||||
void compile(const env_ptr& env, std::vector<instruction_ptr>& into) const;
|
||||
};
|
||||
|
||||
struct ast_lid : public ast {
|
||||
std::string id;
|
||||
|
||||
explicit ast_lid(std::string i)
|
||||
: id(std::move(i)) {}
|
||||
|
||||
void print(int indent, std::ostream& to) const;
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into);
|
||||
type_ptr typecheck(type_mgr& mgr);
|
||||
void compile(const env_ptr& env, std::vector<instruction_ptr>& into) const;
|
||||
};
|
||||
|
||||
struct ast_uid : public ast {
|
||||
std::string id;
|
||||
|
||||
explicit ast_uid(std::string i)
|
||||
: id(std::move(i)) {}
|
||||
|
||||
void print(int indent, std::ostream& to) const;
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into);
|
||||
type_ptr typecheck(type_mgr& mgr);
|
||||
void compile(const env_ptr& env, std::vector<instruction_ptr>& into) const;
|
||||
};
|
||||
|
||||
struct ast_binop : public ast {
|
||||
binop op;
|
||||
ast_ptr left;
|
||||
ast_ptr right;
|
||||
|
||||
ast_binop(binop o, ast_ptr l, ast_ptr r)
|
||||
: op(o), left(std::move(l)), right(std::move(r)) {}
|
||||
|
||||
void print(int indent, std::ostream& to) const;
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into);
|
||||
type_ptr typecheck(type_mgr& mgr);
|
||||
void compile(const env_ptr& env, std::vector<instruction_ptr>& into) const;
|
||||
};
|
||||
|
||||
struct ast_app : public ast {
|
||||
ast_ptr left;
|
||||
ast_ptr right;
|
||||
|
||||
ast_app(ast_ptr l, ast_ptr r)
|
||||
: left(std::move(l)), right(std::move(r)) {}
|
||||
|
||||
void print(int indent, std::ostream& to) const;
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into);
|
||||
type_ptr typecheck(type_mgr& mgr);
|
||||
void compile(const env_ptr& env, std::vector<instruction_ptr>& into) const;
|
||||
};
|
||||
|
||||
struct ast_case : public ast {
|
||||
ast_ptr of;
|
||||
type_ptr input_type;
|
||||
std::vector<branch_ptr> branches;
|
||||
|
||||
ast_case(ast_ptr o, std::vector<branch_ptr> b)
|
||||
: of(std::move(o)), branches(std::move(b)) {}
|
||||
|
||||
void print(int indent, std::ostream& to) const;
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env, std::set<std::string>& into);
|
||||
type_ptr typecheck(type_mgr& mgr);
|
||||
void compile(const env_ptr& env, std::vector<instruction_ptr>& into) const;
|
||||
};
|
||||
|
||||
struct pattern_var : public pattern {
|
||||
std::string var;
|
||||
|
||||
pattern_var(std::string v)
|
||||
: var(std::move(v)) {}
|
||||
|
||||
void print(std::ostream &to) const;
|
||||
void insert_bindings(type_mgr& mgr, type_env_ptr& env) const;
|
||||
void typecheck(type_ptr t, type_mgr& mgr, type_env_ptr& env) const;
|
||||
};
|
||||
|
||||
struct pattern_constr : public pattern {
|
||||
std::string constr;
|
||||
std::vector<std::string> params;
|
||||
|
||||
pattern_constr(std::string c, std::vector<std::string> p)
|
||||
: constr(std::move(c)), params(std::move(p)) {}
|
||||
|
||||
void print(std::ostream &to) const;
|
||||
virtual void insert_bindings(type_mgr& mgr, type_env_ptr& env) const;
|
||||
virtual void typecheck(type_ptr t, type_mgr& mgr, type_env_ptr& env) const;
|
||||
};
|
21
11/binop.cpp
Normal file
21
11/binop.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "binop.hpp"
|
||||
|
||||
std::string op_name(binop op) {
|
||||
switch(op) {
|
||||
case PLUS: return "+";
|
||||
case MINUS: return "-";
|
||||
case TIMES: return "*";
|
||||
case DIVIDE: return "/";
|
||||
}
|
||||
return "??";
|
||||
}
|
||||
|
||||
std::string op_action(binop op) {
|
||||
switch(op) {
|
||||
case PLUS: return "plus";
|
||||
case MINUS: return "minus";
|
||||
case TIMES: return "times";
|
||||
case DIVIDE: return "divide";
|
||||
}
|
||||
return "??";
|
||||
}
|
12
11/binop.hpp
Normal file
12
11/binop.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
enum binop {
|
||||
PLUS,
|
||||
MINUS,
|
||||
TIMES,
|
||||
DIVIDE
|
||||
};
|
||||
|
||||
std::string op_name(binop op);
|
||||
std::string op_action(binop op);
|
99
11/definition.cpp
Normal file
99
11/definition.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "definition.hpp"
|
||||
#include "error.hpp"
|
||||
#include "ast.hpp"
|
||||
#include "instruction.hpp"
|
||||
#include "llvm_context.hpp"
|
||||
#include "type.hpp"
|
||||
#include "type_env.hpp"
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
void definition_defn::find_free(type_mgr& mgr, type_env_ptr& env) {
|
||||
this->env = env;
|
||||
|
||||
var_env = type_scope(env);
|
||||
return_type = mgr.new_type();
|
||||
full_type = return_type;
|
||||
|
||||
for(auto it = params.rbegin(); it != params.rend(); it++) {
|
||||
type_ptr param_type = mgr.new_type();
|
||||
full_type = type_ptr(new type_arr(param_type, full_type));
|
||||
var_env->bind(*it, param_type);
|
||||
}
|
||||
|
||||
body->find_free(mgr, var_env, free_variables);
|
||||
}
|
||||
|
||||
void definition_defn::insert_types(type_mgr& mgr) {
|
||||
env->bind(name, full_type);
|
||||
}
|
||||
|
||||
void definition_defn::typecheck(type_mgr& mgr) {
|
||||
type_ptr body_type = body->typecheck(mgr);
|
||||
mgr.unify(return_type, body_type);
|
||||
}
|
||||
|
||||
void definition_defn::compile() {
|
||||
env_ptr new_env = env_ptr(new env_offset(0, nullptr));
|
||||
for(auto it = params.rbegin(); it != params.rend(); it++) {
|
||||
new_env = env_ptr(new env_var(*it, new_env));
|
||||
}
|
||||
body->compile(new_env, instructions);
|
||||
instructions.push_back(instruction_ptr(new instruction_update(params.size())));
|
||||
instructions.push_back(instruction_ptr(new instruction_pop(params.size())));
|
||||
}
|
||||
|
||||
void definition_defn::declare_llvm(llvm_context& ctx) {
|
||||
generated_function = ctx.create_custom_function(name, params.size());
|
||||
}
|
||||
|
||||
void definition_defn::generate_llvm(llvm_context& ctx) {
|
||||
ctx.builder.SetInsertPoint(&generated_function->getEntryBlock());
|
||||
for(auto& instruction : instructions) {
|
||||
instruction->gen_llvm(ctx, generated_function);
|
||||
}
|
||||
ctx.builder.CreateRetVoid();
|
||||
}
|
||||
|
||||
void definition_data::insert_types(type_mgr& mgr, type_env_ptr& env) {
|
||||
this->env = env;
|
||||
env->bind_type(name, type_ptr(new type_data(name)));
|
||||
}
|
||||
|
||||
void definition_data::insert_constructors() const {
|
||||
type_ptr return_type = env->lookup_type(name);
|
||||
type_data* this_type = static_cast<type_data*>(return_type.get());
|
||||
int next_tag = 0;
|
||||
|
||||
for(auto& constructor : constructors) {
|
||||
constructor->tag = next_tag;
|
||||
this_type->constructors[constructor->name] = { next_tag++ };
|
||||
|
||||
type_ptr full_type = return_type;
|
||||
for(auto it = constructor->types.rbegin(); it != constructor->types.rend(); it++) {
|
||||
type_ptr type = env->lookup_type(*it);
|
||||
if(!type) throw 0;
|
||||
full_type = type_ptr(new type_arr(type, full_type));
|
||||
}
|
||||
|
||||
env->bind(constructor->name, full_type);
|
||||
}
|
||||
}
|
||||
|
||||
void definition_data::generate_llvm(llvm_context& ctx) {
|
||||
for(auto& constructor : constructors) {
|
||||
auto new_function =
|
||||
ctx.create_custom_function(constructor->name, constructor->types.size());
|
||||
std::vector<instruction_ptr> instructions;
|
||||
instructions.push_back(instruction_ptr(
|
||||
new instruction_pack(constructor->tag, constructor->types.size())
|
||||
));
|
||||
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();
|
||||
}
|
||||
}
|
67
11/definition.hpp
Normal file
67
11/definition.hpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "instruction.hpp"
|
||||
#include "llvm_context.hpp"
|
||||
#include "type_env.hpp"
|
||||
|
||||
struct ast;
|
||||
using ast_ptr = std::unique_ptr<ast>;
|
||||
|
||||
struct constructor {
|
||||
std::string name;
|
||||
std::vector<std::string> types;
|
||||
int8_t tag;
|
||||
|
||||
constructor(std::string n, std::vector<std::string> ts)
|
||||
: name(std::move(n)), types(std::move(ts)) {}
|
||||
};
|
||||
|
||||
using constructor_ptr = std::unique_ptr<constructor>;
|
||||
|
||||
struct definition_defn {
|
||||
std::string name;
|
||||
std::vector<std::string> params;
|
||||
ast_ptr body;
|
||||
|
||||
type_env_ptr env;
|
||||
type_env_ptr var_env;
|
||||
std::set<std::string> free_variables;
|
||||
type_ptr full_type;
|
||||
type_ptr return_type;
|
||||
|
||||
std::vector<instruction_ptr> instructions;
|
||||
|
||||
llvm::Function* generated_function;
|
||||
|
||||
definition_defn(std::string n, std::vector<std::string> p, ast_ptr b)
|
||||
: name(std::move(n)), params(std::move(p)), body(std::move(b)) {
|
||||
|
||||
}
|
||||
|
||||
void find_free(type_mgr& mgr, type_env_ptr& env);
|
||||
void insert_types(type_mgr& mgr);
|
||||
void typecheck(type_mgr& mgr);
|
||||
void compile();
|
||||
void declare_llvm(llvm_context& ctx);
|
||||
void generate_llvm(llvm_context& ctx);
|
||||
};
|
||||
|
||||
using definition_defn_ptr = std::unique_ptr<definition_defn>;
|
||||
|
||||
struct definition_data {
|
||||
std::string name;
|
||||
std::vector<constructor_ptr> constructors;
|
||||
|
||||
type_env_ptr env;
|
||||
|
||||
definition_data(std::string n, std::vector<constructor_ptr> cs)
|
||||
: name(std::move(n)), constructors(std::move(cs)) {}
|
||||
|
||||
void insert_types(type_mgr& mgr, type_env_ptr& env);
|
||||
void insert_constructors() const;
|
||||
void generate_llvm(llvm_context& ctx);
|
||||
};
|
||||
|
||||
using definition_data_ptr = std::unique_ptr<definition_data>;
|
23
11/env.cpp
Normal file
23
11/env.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "env.hpp"
|
||||
|
||||
int env_var::get_offset(const std::string& name) const {
|
||||
if(name == this->name) return 0;
|
||||
if(parent) return parent->get_offset(name) + 1;
|
||||
throw 0;
|
||||
}
|
||||
|
||||
bool env_var::has_variable(const std::string& name) const {
|
||||
if(name == this->name) return true;
|
||||
if(parent) return parent->has_variable(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
int env_offset::get_offset(const std::string& name) const {
|
||||
if(parent) return parent->get_offset(name) + offset;
|
||||
throw 0;
|
||||
}
|
||||
|
||||
bool env_offset::has_variable(const std::string& name) const {
|
||||
if(parent) return parent->has_variable(name);
|
||||
return false;
|
||||
}
|
34
11/env.hpp
Normal file
34
11/env.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct env {
|
||||
virtual ~env() = default;
|
||||
|
||||
virtual int get_offset(const std::string& name) const = 0;
|
||||
virtual bool has_variable(const std::string& name) const = 0;
|
||||
};
|
||||
|
||||
using env_ptr = std::shared_ptr<env>;
|
||||
|
||||
struct env_var : public env {
|
||||
std::string name;
|
||||
env_ptr parent;
|
||||
|
||||
env_var(std::string& n, env_ptr p)
|
||||
: name(std::move(n)), parent(std::move(p)) {}
|
||||
|
||||
int get_offset(const std::string& name) const;
|
||||
bool has_variable(const std::string& name) const;
|
||||
};
|
||||
|
||||
struct env_offset : public env {
|
||||
int offset;
|
||||
env_ptr parent;
|
||||
|
||||
env_offset(int o, env_ptr p)
|
||||
: offset(o), parent(std::move(p)) {}
|
||||
|
||||
int get_offset(const std::string& name) const;
|
||||
bool has_variable(const std::string& name) const;
|
||||
};
|
5
11/error.cpp
Normal file
5
11/error.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include "error.hpp"
|
||||
|
||||
const char* type_error::what() const noexcept {
|
||||
return "an error occured while checking the types of the program";
|
||||
}
|
21
11/error.hpp
Normal file
21
11/error.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include <exception>
|
||||
#include "type.hpp"
|
||||
|
||||
struct type_error : std::exception {
|
||||
std::string description;
|
||||
|
||||
type_error(std::string d)
|
||||
: description(std::move(d)) {}
|
||||
|
||||
const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
struct unification_error : public type_error {
|
||||
type_ptr left;
|
||||
type_ptr right;
|
||||
|
||||
unification_error(type_ptr l, type_ptr r)
|
||||
: left(std::move(l)), right(std::move(r)),
|
||||
type_error("failed to unify types") {}
|
||||
};
|
2
11/examples/bad1.txt
Normal file
2
11/examples/bad1.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
data Bool = { True, False }
|
||||
defn main = { 3 + True }
|
1
11/examples/bad2.txt
Normal file
1
11/examples/bad2.txt
Normal file
|
@ -0,0 +1 @@
|
|||
defn main = { 1 2 3 4 5 }
|
8
11/examples/bad3.txt
Normal file
8
11/examples/bad3.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
data List = { Nil, Cons Int List }
|
||||
|
||||
defn head l = {
|
||||
case l of {
|
||||
Nil -> { 0 }
|
||||
Cons x y z -> { x }
|
||||
}
|
||||
}
|
8
11/examples/if.txt
Normal file
8
11/examples/if.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
data Bool = { True, False }
|
||||
defn if c t e = {
|
||||
case c of {
|
||||
True -> { t }
|
||||
False -> { e }
|
||||
}
|
||||
}
|
||||
defn main = { if (if True False True) 11 3 }
|
25
11/examples/mutual_recursion.txt
Normal file
25
11/examples/mutual_recursion.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
data Bool = { True, False }
|
||||
data List = { Nil, Cons Int List }
|
||||
|
||||
defn if c t e = {
|
||||
case c of {
|
||||
True -> { t }
|
||||
False -> { e }
|
||||
}
|
||||
}
|
||||
|
||||
defn oddEven l e = {
|
||||
case l of {
|
||||
Nil -> { e }
|
||||
Cons x xs -> { evenOdd xs e }
|
||||
}
|
||||
}
|
||||
|
||||
defn evenOdd l e = {
|
||||
case l of {
|
||||
Nil -> { e }
|
||||
Cons x xs -> { oddEven xs e }
|
||||
}
|
||||
}
|
||||
|
||||
defn main = { if (oddEven (Cons 1 (Cons 2 (Cons 3 Nil))) True) (oddEven (Cons 1 (Cons 2 (Cons 3 Nil))) 1) 3 }
|
122
11/examples/primes.txt
Normal file
122
11/examples/primes.txt
Normal file
|
@ -0,0 +1,122 @@
|
|||
data List = { Nil, Cons Nat List }
|
||||
data Bool = { True, False }
|
||||
data Nat = { O, S Nat }
|
||||
|
||||
defn if c t e = {
|
||||
case c of {
|
||||
True -> { t }
|
||||
False -> { e }
|
||||
}
|
||||
}
|
||||
|
||||
defn toInt n = {
|
||||
case n of {
|
||||
O -> { 0 }
|
||||
S np -> { 1 + toInt np }
|
||||
}
|
||||
}
|
||||
|
||||
defn lte n m = {
|
||||
case m of {
|
||||
O -> {
|
||||
case n of {
|
||||
O -> { True }
|
||||
S np -> { False }
|
||||
}
|
||||
}
|
||||
S mp -> {
|
||||
case n of {
|
||||
O -> { True }
|
||||
S np -> { lte np mp }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defn minus n m = {
|
||||
case m of {
|
||||
O -> { n }
|
||||
S mp -> {
|
||||
case n of {
|
||||
O -> { O }
|
||||
S np -> {
|
||||
minus np mp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defn mod n m = {
|
||||
if (lte m n) (mod (minus n m) m) n
|
||||
}
|
||||
|
||||
defn notDivisibleBy n m = {
|
||||
case (mod m n) of {
|
||||
O -> { False }
|
||||
S mp -> { True }
|
||||
}
|
||||
}
|
||||
|
||||
defn filter f l = {
|
||||
case l of {
|
||||
Nil -> { Nil }
|
||||
Cons x xs -> { if (f x) (Cons x (filter f xs)) (filter f xs) }
|
||||
}
|
||||
}
|
||||
|
||||
defn map f l = {
|
||||
case l of {
|
||||
Nil -> { Nil }
|
||||
Cons x xs -> { Cons (f x) (map f xs) }
|
||||
}
|
||||
}
|
||||
|
||||
defn nats = {
|
||||
Cons (S (S O)) (map S nats)
|
||||
}
|
||||
|
||||
defn primesRec l = {
|
||||
case l of {
|
||||
Nil -> { Nil }
|
||||
Cons p xs -> { Cons p (primesRec (filter (notDivisibleBy p) xs)) }
|
||||
}
|
||||
}
|
||||
|
||||
defn primes = {
|
||||
primesRec nats
|
||||
}
|
||||
|
||||
defn take n l = {
|
||||
case l of {
|
||||
Nil -> { Nil }
|
||||
Cons x xs -> {
|
||||
case n of {
|
||||
O -> { Nil }
|
||||
S np -> { Cons x (take np xs) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defn head l = {
|
||||
case l of {
|
||||
Nil -> { O }
|
||||
Cons x xs -> { x }
|
||||
}
|
||||
}
|
||||
|
||||
defn reverseAcc a l = {
|
||||
case l of {
|
||||
Nil -> { a }
|
||||
Cons x xs -> { reverseAcc (Cons x a) xs }
|
||||
}
|
||||
}
|
||||
|
||||
defn reverse l = {
|
||||
reverseAcc Nil l
|
||||
}
|
||||
|
||||
defn main = {
|
||||
toInt (head (reverse (take ((S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) primes)))
|
||||
}
|
31
11/examples/runtime1.c
Normal file
31
11/examples/runtime1.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "../runtime.h"
|
||||
|
||||
void f_add(struct stack* s) {
|
||||
struct node_num* left = (struct node_num*) eval(stack_peek(s, 0));
|
||||
struct node_num* right = (struct node_num*) eval(stack_peek(s, 1));
|
||||
stack_push(s, (struct node_base*) alloc_num(left->value + right->value));
|
||||
}
|
||||
|
||||
void f_main(struct stack* s) {
|
||||
// PushInt 320
|
||||
stack_push(s, (struct node_base*) alloc_num(320));
|
||||
|
||||
// PushInt 6
|
||||
stack_push(s, (struct node_base*) alloc_num(6));
|
||||
|
||||
// PushGlobal f_add (the function for +)
|
||||
stack_push(s, (struct node_base*) alloc_global(f_add, 2));
|
||||
|
||||
struct node_base* left;
|
||||
struct node_base* right;
|
||||
|
||||
// MkApp
|
||||
left = stack_pop(s);
|
||||
right = stack_pop(s);
|
||||
stack_push(s, (struct node_base*) alloc_app(left, right));
|
||||
|
||||
// MkApp
|
||||
left = stack_pop(s);
|
||||
right = stack_pop(s);
|
||||
stack_push(s, (struct node_base*) alloc_app(left, right));
|
||||
}
|
2
11/examples/works1.txt
Normal file
2
11/examples/works1.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
defn main = { sum 320 6 }
|
||||
defn sum x y = { x + y }
|
3
11/examples/works2.txt
Normal file
3
11/examples/works2.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
defn add x y = { x + y }
|
||||
defn double x = { add x x }
|
||||
defn main = { double 163 }
|
9
11/examples/works3.txt
Normal file
9
11/examples/works3.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
data List = { Nil, Cons Int List }
|
||||
data Bool = { True, False }
|
||||
defn length l = {
|
||||
case l of {
|
||||
Nil -> { 0 }
|
||||
Cons x xs -> { 1 + length xs }
|
||||
}
|
||||
}
|
||||
defn main = { length (Cons True (Cons False (Cons True Nil))) }
|
16
11/examples/works4.txt
Normal file
16
11/examples/works4.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
data List = { Nil, Cons Int List }
|
||||
|
||||
defn add x y = { x + y }
|
||||
defn mul x y = { x * y }
|
||||
|
||||
defn foldr f b l = {
|
||||
case l of {
|
||||
Nil -> { b }
|
||||
Cons x xs -> { f x (foldr f b xs) }
|
||||
}
|
||||
}
|
||||
|
||||
defn main = {
|
||||
foldr add 0 (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))) +
|
||||
foldr mul 1 (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil))))
|
||||
}
|
17
11/examples/works5.txt
Normal file
17
11/examples/works5.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
data List = { Nil, Cons Int List }
|
||||
|
||||
defn sumZip l m = {
|
||||
case l of {
|
||||
Nil -> { 0 }
|
||||
Cons x xs -> {
|
||||
case m of {
|
||||
Nil -> { 0 }
|
||||
Cons y ys -> { x + y + sumZip xs ys }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defn ones = { Cons 1 ones }
|
||||
|
||||
defn main = { sumZip ones (Cons 1 (Cons 2 (Cons 3 Nil))) }
|
114
11/graph.cpp
Normal file
114
11/graph.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include "graph.hpp"
|
||||
|
||||
std::set<function_graph::edge> function_graph::compute_transitive_edges() {
|
||||
std::set<edge> transitive_edges;
|
||||
transitive_edges.insert(edges.begin(), edges.end());
|
||||
for(auto& connector : adjacency_lists) {
|
||||
for(auto& from : adjacency_lists) {
|
||||
edge to_connector { from.first, connector.first };
|
||||
for(auto& to : adjacency_lists) {
|
||||
edge full_jump { from.first, to.first };
|
||||
if(transitive_edges.find(full_jump) != transitive_edges.end()) continue;
|
||||
|
||||
edge from_connector { connector.first, to.first };
|
||||
if(transitive_edges.find(to_connector) != transitive_edges.end() &&
|
||||
transitive_edges.find(from_connector) != transitive_edges.end())
|
||||
transitive_edges.insert(std::move(full_jump));
|
||||
}
|
||||
}
|
||||
}
|
||||
return transitive_edges;
|
||||
}
|
||||
|
||||
void function_graph::create_groups(
|
||||
const std::set<edge>& transitive_edges,
|
||||
std::map<function, group_id>& group_ids,
|
||||
std::map<group_id, data_ptr>& group_data_map) {
|
||||
group_id id_counter = 0;
|
||||
for(auto& vertex : adjacency_lists) {
|
||||
if(group_ids.find(vertex.first) != group_ids.end())
|
||||
continue;
|
||||
data_ptr new_group(new group_data);
|
||||
new_group->functions.insert(vertex.first);
|
||||
group_data_map[id_counter] = new_group;
|
||||
group_ids[vertex.first] = id_counter;
|
||||
for(auto& other_vertex : adjacency_lists) {
|
||||
if(transitive_edges.find({vertex.first, other_vertex.first}) != transitive_edges.end() &&
|
||||
transitive_edges.find({other_vertex.first, vertex.first}) != transitive_edges.end()) {
|
||||
group_ids[other_vertex.first] = id_counter;
|
||||
new_group->functions.insert(other_vertex.first);
|
||||
}
|
||||
}
|
||||
id_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
void function_graph::create_edges(
|
||||
std::map<function, group_id>& group_ids,
|
||||
std::map<group_id, data_ptr>& group_data_map) {
|
||||
std::set<std::pair<group_id, group_id>> group_edges;
|
||||
for(auto& vertex : adjacency_lists) {
|
||||
auto vertex_id = group_ids[vertex.first];
|
||||
auto& vertex_data = group_data_map[vertex_id];
|
||||
for(auto& other_vertex : vertex.second) {
|
||||
auto other_id = group_ids[other_vertex];
|
||||
if(vertex_id == other_id) continue;
|
||||
if(group_edges.find({vertex_id, other_id}) != group_edges.end())
|
||||
continue;
|
||||
group_edges.insert({vertex_id, other_id});
|
||||
vertex_data->adjacency_list.insert(other_id);
|
||||
group_data_map[other_id]->indegree++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<group_ptr> function_graph::generate_order(
|
||||
std::map<function, group_id>& group_ids,
|
||||
std::map<group_id, data_ptr>& group_data_map) {
|
||||
std::queue<group_id> id_queue;
|
||||
std::vector<group_ptr> output;
|
||||
for(auto& group : group_data_map) {
|
||||
if(group.second->indegree == 0) id_queue.push(group.first);
|
||||
}
|
||||
|
||||
while(!id_queue.empty()) {
|
||||
auto new_id = id_queue.front();
|
||||
auto& group_data = group_data_map[new_id];
|
||||
group_ptr output_group(new group);
|
||||
output_group->members = std::move(group_data->functions);
|
||||
id_queue.pop();
|
||||
|
||||
for(auto& adjacent_group : group_data->adjacency_list) {
|
||||
if(--group_data_map[adjacent_group]->indegree == 0)
|
||||
id_queue.push(adjacent_group);
|
||||
}
|
||||
|
||||
output.push_back(std::move(output_group));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::set<function>& function_graph::add_function(const function& f) {
|
||||
auto adjacency_list_it = adjacency_lists.find(f);
|
||||
if(adjacency_list_it != adjacency_lists.end()) {
|
||||
return adjacency_list_it->second;
|
||||
} else {
|
||||
return adjacency_lists[f] = { };
|
||||
}
|
||||
}
|
||||
|
||||
void function_graph::add_edge(const function& from, const function& to) {
|
||||
add_function(from).insert(to);
|
||||
edges.insert({ from, to });
|
||||
}
|
||||
|
||||
std::vector<group_ptr> function_graph::compute_order() {
|
||||
std::set<edge> transitive_edges = compute_transitive_edges();
|
||||
std::map<function, group_id> group_ids;
|
||||
std::map<group_id, data_ptr> group_data_map;
|
||||
|
||||
create_groups(transitive_edges, group_ids, group_data_map);
|
||||
create_edges(group_ids, group_data_map);
|
||||
return generate_order(group_ids, group_data_map);
|
||||
}
|
52
11/graph.hpp
Normal file
52
11/graph.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using function = std::string;
|
||||
|
||||
struct group {
|
||||
std::set<function> members;
|
||||
};
|
||||
|
||||
using group_ptr = std::unique_ptr<group>;
|
||||
|
||||
class function_graph {
|
||||
using group_id = size_t;
|
||||
|
||||
struct group_data {
|
||||
std::set<function> functions;
|
||||
std::set<group_id> adjacency_list;
|
||||
size_t indegree;
|
||||
};
|
||||
|
||||
using data_ptr = std::shared_ptr<group_data>;
|
||||
using edge = std::pair<function, function>;
|
||||
using group_edge = std::pair<group_id, group_id>;
|
||||
|
||||
std::map<function, std::set<function>> adjacency_lists;
|
||||
std::set<edge> edges;
|
||||
|
||||
std::set<edge> compute_transitive_edges();
|
||||
void create_groups(
|
||||
const std::set<edge>&,
|
||||
std::map<function, group_id>&,
|
||||
std::map<group_id, data_ptr>&);
|
||||
void create_edges(
|
||||
std::map<function, group_id>&,
|
||||
std::map<group_id, data_ptr>&);
|
||||
std::vector<group_ptr> generate_order(
|
||||
std::map<function, group_id>&,
|
||||
std::map<group_id, data_ptr>&);
|
||||
|
||||
public:
|
||||
std::set<function>& add_function(const function& f);
|
||||
void add_edge(const function& from, const function& to);
|
||||
std::vector<group_ptr> compute_order();
|
||||
};
|
177
11/instruction.cpp
Normal file
177
11/instruction.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
#include "instruction.hpp"
|
||||
#include "llvm_context.hpp"
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static void print_indent(int n, std::ostream& to) {
|
||||
while(n--) to << " ";
|
||||
}
|
||||
|
||||
void instruction_pushint::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "PushInt(" << value << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_pushint::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_push(f, ctx.create_num(f, ctx.create_i32(value)));
|
||||
}
|
||||
|
||||
void instruction_pushglobal::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "PushGlobal(" << name << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_pushglobal::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
auto& global_f = ctx.custom_functions.at("f_" + name);
|
||||
auto arity = ctx.create_i32(global_f->arity);
|
||||
ctx.create_push(f, ctx.create_global(f, global_f->function, arity));
|
||||
}
|
||||
|
||||
void instruction_push::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Push(" << offset << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_push::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_push(f, ctx.create_peek(f, ctx.create_size(offset)));
|
||||
}
|
||||
|
||||
void instruction_pop::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Pop(" << count << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_pop::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_popn(f, ctx.create_size(count));
|
||||
}
|
||||
|
||||
void instruction_mkapp::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "MkApp()" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_mkapp::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
auto left = ctx.create_pop(f);
|
||||
auto right = ctx.create_pop(f);
|
||||
ctx.create_push(f, ctx.create_app(f, left, right));
|
||||
}
|
||||
|
||||
void instruction_update::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Update(" << offset << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_update::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_update(f, ctx.create_size(offset));
|
||||
}
|
||||
|
||||
void instruction_pack::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Pack(" << tag << ", " << size << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_pack::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_pack(f, ctx.create_size(size), ctx.create_i8(tag));
|
||||
}
|
||||
|
||||
void instruction_split::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Split()" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_split::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_split(f, ctx.create_size(size));
|
||||
}
|
||||
|
||||
void instruction_jump::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Jump(" << std::endl;
|
||||
for(auto& instruction_set : branches) {
|
||||
for(auto& instruction : instruction_set) {
|
||||
instruction->print(indent + 2, to);
|
||||
}
|
||||
to << std::endl;
|
||||
}
|
||||
print_indent(indent, to);
|
||||
to << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
auto top_node = ctx.create_peek(f, ctx.create_size(0));
|
||||
auto tag = ctx.unwrap_data_tag(top_node);
|
||||
auto safety_block = BasicBlock::Create(ctx.ctx, "safety", f);
|
||||
auto switch_op = ctx.builder.CreateSwitch(tag, safety_block, tag_mappings.size());
|
||||
std::vector<BasicBlock*> blocks;
|
||||
|
||||
for(auto& branch : branches) {
|
||||
auto branch_block = BasicBlock::Create(ctx.ctx, "branch", f);
|
||||
ctx.builder.SetInsertPoint(branch_block);
|
||||
for(auto& instruction : branch) {
|
||||
instruction->gen_llvm(ctx, f);
|
||||
}
|
||||
ctx.builder.CreateBr(safety_block);
|
||||
blocks.push_back(branch_block);
|
||||
}
|
||||
|
||||
for(auto& mapping : tag_mappings) {
|
||||
switch_op->addCase(ctx.create_i8(mapping.first), blocks[mapping.second]);
|
||||
}
|
||||
|
||||
ctx.builder.SetInsertPoint(safety_block);
|
||||
}
|
||||
|
||||
void instruction_slide::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Slide(" << offset << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_slide::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_slide(f, ctx.create_size(offset));
|
||||
}
|
||||
|
||||
void instruction_binop::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "BinOp(" << op_action(op) << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
auto left_int = ctx.unwrap_num(ctx.create_pop(f));
|
||||
auto right_int = ctx.unwrap_num(ctx.create_pop(f));
|
||||
llvm::Value* result;
|
||||
switch(op) {
|
||||
case PLUS: result = ctx.builder.CreateAdd(left_int, right_int); break;
|
||||
case MINUS: result = ctx.builder.CreateSub(left_int, right_int); break;
|
||||
case TIMES: result = ctx.builder.CreateMul(left_int, right_int); break;
|
||||
case DIVIDE: result = ctx.builder.CreateSDiv(left_int, right_int); break;
|
||||
}
|
||||
ctx.create_push(f, ctx.create_num(f, result));
|
||||
}
|
||||
|
||||
void instruction_eval::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Eval()" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_eval::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_unwind(f);
|
||||
}
|
||||
|
||||
void instruction_alloc::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Alloc(" << amount << ")" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_alloc::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
ctx.create_alloc(f, ctx.create_size(amount));
|
||||
}
|
||||
|
||||
void instruction_unwind::print(int indent, std::ostream& to) const {
|
||||
print_indent(indent, to);
|
||||
to << "Unwind()" << std::endl;
|
||||
}
|
||||
|
||||
void instruction_unwind::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||
// Nothing
|
||||
}
|
142
11/instruction.hpp
Normal file
142
11/instruction.hpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
#pragma once
|
||||
#include <llvm/IR/Function.h>
|
||||