Roll back optimization changes.

This commit is contained in:
Danila Fedorin 2020-09-17 20:14:39 -07:00
parent 02f8306c7b
commit 8a352ed3ea
14 changed files with 78 additions and 833 deletions

View File

@ -212,6 +212,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())) ||
!dynamic_cast<type_data*>(app_type->constructor.get())) {
throw type_error("attempting case analysis of non-data type");
}
return branch_type; return branch_type;
} }
@ -223,219 +227,60 @@ void ast_case::translate(global_scope& scope) {
} }
} }
template <typename T>
struct case_mappings {
using tag_type = typename T::tag_type;
std::map<tag_type, std::vector<instruction_ptr>> defined_cases;
std::optional<std::vector<instruction_ptr>> default_case;
std::vector<instruction_ptr>& make_case_for(tag_type tag) {
if(default_case)
throw compiler_error("attempted pattern match after catch-all");
return defined_cases[tag];
}
std::vector<instruction_ptr>& make_default_case() {
if(default_case)
throw compiler_error("attempted repeated use of catch-all");
default_case.emplace(std::vector<instruction_ptr>());
return *default_case;
}
std::vector<instruction_ptr>& get_specific_case_for(tag_type tag) {
auto existing_case = defined_cases.find(tag);
assert(existing_case != defined_cases.end());
return existing_case->second;
}
std::vector<instruction_ptr>& get_default_case() {
assert(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) {
return defined_cases.find(tag) != defined_cases.end();
}
bool default_case_defined() { return default_case.has_value(); }
size_t defined_cases_count() { return defined_cases.size(); }
};
struct case_strategy_bool {
using tag_type = bool;
using repr_type = bool;
case_strategy_bool(const type* type) {}
tag_type tag_from_repr(repr_type b) { return b; }
repr_type repr_from_pattern(const pattern_ptr& pt) {
pattern_constr* cpat;
if(!(cpat = dynamic_cast<pattern_constr*>(pt.get())) ||
(cpat->constr != "True" && cpat->constr != "False") ||
cpat->params.size() != 0)
throw compiler_error(
"pattern cannot be converted to a boolean",
pt->loc);
return cpat->constr == "True";
}
void compile_branch(
const branch_ptr& branch,
const env_ptr& env,
repr_type repr,
std::vector<instruction_ptr>& into) {
branch->expr->compile(env_ptr(new env_offset(1, env)), into);
into.push_back(instruction_ptr(new instruction_slide(1)));
}
size_t case_count() {
return 2;
}
void into_instructions(
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;
}
instruction_ijump* ijump = new instruction_ijump();
instruction_ptr inst(ijump);
ijump->branches.push_back(std::move(ms.get_case_for(false)));
ijump->tag_mappings[0] = 0;
ijump->branches.push_back(std::move(ms.get_case_for(true)));
ijump->tag_mappings[1] = 1;
into.push_back(std::move(inst));
}
};
struct case_strategy_data {
using tag_type = int;
using repr_type = std::pair<const type_data::constructor*, const std::vector<std::string>*>;
const type_data* arg_type;
case_strategy_data(const type* t) {
arg_type = dynamic_cast<const type_data*>(t);
assert(arg_type);
}
tag_type tag_from_repr(const repr_type& repr) { return repr.first->tag; }
repr_type repr_from_pattern(const pattern_ptr& pt) {
pattern_constr* cpat;
if(!(cpat = dynamic_cast<pattern_constr*>(pt.get())))
throw compiler_error(
"pattern cannot be interpreted as constructor.",
pt->loc);
return std::make_pair(
&arg_type->constructors.find(cpat->constr)->second,
&cpat->params);
}
void compile_branch(
const branch_ptr& branch,
const env_ptr& env,
const repr_type& repr,
std::vector<instruction_ptr>& into) {
env_ptr new_env = env;
for(auto it = repr.second->rbegin(); it != repr.second->rend(); it++) {
new_env = env_ptr(new env_var(*it, new_env));
}
into.push_back(instruction_ptr(new instruction_split(repr.second->size())));
branch->expr->compile(new_env, into);
into.push_back(instruction_ptr(new instruction_slide(repr.second->size())));
}
size_t case_count() {
return arg_type->constructors.size();
}
void into_instructions(
case_mappings<case_strategy_data>& ms,
std::vector<instruction_ptr>& into) {
instruction_jump* jump_instruction = new instruction_jump();
instruction_ptr inst(jump_instruction);
for(auto& constr : arg_type->constructors) {
if(!ms.case_defined_for(constr.second.tag)) continue;
jump_instruction->branches.push_back(
std::move(ms.get_specific_case_for(constr.second.tag)));
jump_instruction->tag_mappings[constr.second.tag] =
jump_instruction->branches.size() - 1;
}
if(ms.default_case_defined()) {
jump_instruction->branches.push_back(
std::move(ms.get_default_case()));
for(auto& constr : arg_type->constructors) {
if(ms.case_defined_for(constr.second.tag)) continue;
jump_instruction->tag_mappings[constr.second.tag] =
jump_instruction->branches.size();
}
}
into.push_back(std::move(inst));
}
};
template <typename T>
void compile_case(const ast_case& node, const env_ptr& env, const type* type, std::vector<instruction_ptr>& into) {
T strategy(type);
case_mappings<T> cases;
for(auto& branch : node.branches) {
pattern_var* vpat;
if((vpat = dynamic_cast<pattern_var*>(branch->pat.get()))) {
if(cases.defined_cases_count() == strategy.case_count())
throw compiler_error("redundant catch-all pattern", branch->pat->loc);
auto& branch_into = cases.make_default_case();
env_ptr new_env(new env_var(vpat->var, env));
branch->expr->compile(new_env, branch_into);
branch_into.push_back(instruction_ptr(new instruction_slide(1)));
} else {
auto repr = strategy.repr_from_pattern(branch->pat);
auto& branch_into = cases.make_case_for(strategy.tag_from_repr(repr));
strategy.compile_branch(branch, env, repr, branch_into);
}
}
if(!(cases.defined_cases_count() == strategy.case_count() ||
cases.default_case_defined()))
throw compiler_error("incomplete patterns", node.loc);
strategy.into_instructions(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 {
type_app* app_type = dynamic_cast<type_app*>(input_type.get()); type_app* app_type = dynamic_cast<type_app*>(input_type.get());
type_data* data; type_data* type = dynamic_cast<type_data*>(app_type->constructor.get());
type_base *base;
of->compile(env, into); of->compile(env, into);
into.push_back(instruction_ptr(new instruction_eval())); into.push_back(instruction_ptr(new instruction_eval()));
if(app_type && (data = dynamic_cast<type_data*>(app_type->constructor.get()))) { instruction_jump* jump_instruction = new instruction_jump();
compile_case<case_strategy_data>(*this, env, data, into); into.push_back(instruction_ptr(jump_instruction));
return; for(auto& branch : branches) {
} else if (app_type && (base = dynamic_cast<type_base *>(app_type->constructor.get()))) { std::vector<instruction_ptr> branch_instructions;
if (base->name == "Bool") { pattern_var* vpat;
compile_case<case_strategy_bool>(*this, env, data, into); pattern_constr* cpat;
return;
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));
} }
} }
throw type_error("attempting unsupported case analysis", of->loc); 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 ast_let::print(int indent, std::ostream& to) const { void ast_let::print(int indent, std::ostream& to) const {

View File

@ -6,9 +6,6 @@ std::string op_name(binop op) {
case MINUS: return "-"; case MINUS: return "-";
case TIMES: return "*"; case TIMES: return "*";
case DIVIDE: return "/"; case DIVIDE: return "/";
case MODULO: return "%";
case EQUALS: return "==";
case LESS_EQUALS: return "<=";
} }
return "??"; return "??";
} }
@ -19,9 +16,6 @@ std::string op_action(binop op) {
case MINUS: return "minus"; case MINUS: return "minus";
case TIMES: return "times"; case TIMES: return "times";
case DIVIDE: return "divide"; case DIVIDE: return "divide";
case MODULO: return "modulo";
case EQUALS: return "equals";
case LESS_EQUALS: return "less_equals";
} }
return "??"; return "??";
} }

View File

@ -6,15 +6,11 @@ enum binop {
PLUS, PLUS,
MINUS, MINUS,
TIMES, TIMES,
DIVIDE, DIVIDE
MODULO,
EQUALS,
LESS_EQUALS,
}; };
constexpr binop all_binops[] = { constexpr binop all_binops[] = {
PLUS, MINUS, TIMES, DIVIDE, MODULO, PLUS, MINUS, TIMES, DIVIDE
EQUALS, LESS_EQUALS
}; };
std::string op_name(binop op); std::string op_name(binop op);

View File

@ -17,7 +17,6 @@
void compiler::add_default_types() { void compiler::add_default_types() {
global_env->bind_type("Int", type_ptr(new type_base("Int"))); global_env->bind_type("Int", type_ptr(new type_base("Int")));
global_env->bind_type("Bool", type_ptr(new type_base("Bool")));
} }
void compiler::add_binop_type(binop op, type_ptr type) { void compiler::add_binop_type(binop op, type_ptr type) {
@ -31,24 +30,11 @@ void compiler::add_default_function_types() {
assert(int_type != nullptr); assert(int_type != nullptr);
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 = global_env->lookup_type("Bool");
assert(bool_type != nullptr);
type_ptr bool_type_app = type_ptr(new type_app(bool_type));
type_ptr closed_int_op_type( type_ptr closed_int_op_type(
new type_arr(int_type_app, type_ptr(new type_arr(int_type_app, int_type_app)))); new type_arr(int_type_app, type_ptr(new type_arr(int_type_app, int_type_app))));
type_ptr compare_int_op_type(
new type_arr(int_type_app, type_ptr(new type_arr(int_type_app, bool_type_app))));
constexpr binop closed_ops[] = { PLUS, MINUS, TIMES, DIVIDE, MODULO }; constexpr binop closed_ops[] = { PLUS, MINUS, TIMES, DIVIDE };
constexpr binop compare_ops[] = { EQUALS, LESS_EQUALS };
for(auto& op : closed_ops) add_binop_type(op, closed_int_op_type); for(auto& op : closed_ops) add_binop_type(op, closed_int_op_type);
for(auto& op : compare_ops) add_binop_type(op, compare_int_op_type);
for(auto name : { "True", "False" }) {
global_env->bind(name, bool_type_app, visibility::global);
global_env->set_mangled_name(name, mng.new_mangled_name(name));
}
} }
void compiler::parse() { void compiler::parse() {
@ -94,25 +80,10 @@ void compiler::create_llvm_binop(binop op) {
ctx.get_builder().CreateRetVoid(); ctx.get_builder().CreateRetVoid();
} }
void compiler::create_llvm_bool(bool b) {
auto new_function = ctx.create_custom_function(
global_env->get_mangled_name(b ? "True" : "False"), 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.get_builder().SetInsertPoint(&new_function->getEntryBlock());
for(auto& instruction : instructions) {
instruction->gen_llvm(ctx, new_function);
}
ctx.get_builder().CreateRetVoid();
}
void compiler::generate_llvm() { void compiler::generate_llvm() {
for(auto op : all_binops) { for(auto op : all_binops) {
create_llvm_binop(op); create_llvm_binop(op);
} }
create_llvm_bool(true);
create_llvm_bool(false);
global_scp.generate_llvm(ctx); global_scp.generate_llvm(ctx);
} }

View File

@ -27,7 +27,6 @@ class compiler {
void translate(); void translate();
void compile(); void compile();
void create_llvm_binop(binop op); void create_llvm_binop(binop op);
void create_llvm_bool(bool b);
void generate_llvm(); void generate_llvm();
void output_llvm(const std::string& into); void output_llvm(const std::string& into);
public: public:

View File

@ -100,7 +100,7 @@ void instruction_jump::print(int indent, std::ostream& to) const {
void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const { void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
auto top_node = ctx.create_peek(f, ctx.create_size(0)); auto top_node = ctx.create_peek(f, ctx.create_size(0));
auto tag = get_case_value(ctx, top_node); auto tag = ctx.unwrap_data_tag(top_node);
auto safety_block = ctx.create_basic_block("safety", f); auto safety_block = ctx.create_basic_block("safety", f);
auto switch_op = ctx.get_builder().CreateSwitch(tag, safety_block, tag_mappings.size()); auto switch_op = ctx.get_builder().CreateSwitch(tag, safety_block, tag_mappings.size());
std::vector<BasicBlock*> blocks; std::vector<BasicBlock*> blocks;
@ -122,14 +122,6 @@ void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.get_builder().SetInsertPoint(safety_block); ctx.get_builder().SetInsertPoint(safety_block);
} }
Value* instruction_jump::get_case_value(llvm_context& ctx, Value* v) const {
return ctx.unwrap_data_tag(v);
}
Value* instruction_ijump::get_case_value(llvm_context& ctx, Value* v) const {
return ctx.unwrap_num(v);
}
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;
@ -153,9 +145,6 @@ void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const {
case MINUS: result = ctx.get_builder().CreateSub(left_int, right_int); break; case MINUS: result = ctx.get_builder().CreateSub(left_int, right_int); break;
case TIMES: result = ctx.get_builder().CreateMul(left_int, right_int); break; case TIMES: result = ctx.get_builder().CreateMul(left_int, right_int); break;
case DIVIDE: result = ctx.get_builder().CreateSDiv(left_int, right_int); break; case DIVIDE: result = ctx.get_builder().CreateSDiv(left_int, right_int); break;
case MODULO: result = ctx.get_builder().CreateSRem(left_int, right_int); break;
case EQUALS: result = ctx.get_builder().CreateICmpEQ(left_int, right_int); break;
case LESS_EQUALS: result = ctx.get_builder().CreateICmpSLE(left_int, right_int); break;
} }
ctx.create_push(f, ctx.create_num(f, result)); ctx.create_push(f, ctx.create_num(f, result));
} }

View File

@ -99,12 +99,6 @@ struct instruction_jump : public instruction {
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const; void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
virtual llvm::Value* get_case_value(llvm_context& ctx, llvm::Value*) const;
};
struct instruction_ijump : public instruction_jump {
llvm::Value* get_case_value(llvm_context& ctx, llvm::Value*) const;
}; };
struct instruction_slide : public instruction { struct instruction_slide : public instruction {

View File

@ -237,7 +237,12 @@ Value* llvm_context::unwrap_gmachine_stack_ptr(Value* g) {
} }
Value* llvm_context::unwrap_num(Value* v) { Value* llvm_context::unwrap_num(Value* v) {
return builder.CreatePtrToInt(v, IntegerType::getInt32Ty(ctx)); auto num_ptr_type = PointerType::getUnqual(struct_types.at("node_num"));
auto cast = builder.CreatePointerCast(v, num_ptr_type);
auto offset_0 = create_i32(0);
auto offset_1 = create_i32(1);
auto int_ptr = builder.CreateGEP(cast, { offset_0, offset_1 });
return builder.CreateLoad(int_ptr);
} }
Value* llvm_context::create_num(Function* f, Value* v) { Value* llvm_context::create_num(Function* f, Value* v) {
auto alloc_num_f = functions.at("alloc_num"); auto alloc_num_f = functions.at("alloc_num");

View File

@ -18,14 +18,10 @@ using yyscan_t = void*;
} }
%token BACKSLASH %token BACKSLASH
%token BACKTICK
%token PLUS %token PLUS
%token TIMES %token TIMES
%token MINUS %token MINUS
%token DIVIDE %token DIVIDE
%token MODULO
%token EQUALS
%token LESS_EQUALS
%token <int> INT %token <int> INT
%token DEFN %token DEFN
%token DATA %token DATA
@ -53,10 +49,9 @@ using yyscan_t = void*;
%type <std::vector<branch_ptr>> branches %type <std::vector<branch_ptr>> branches
%type <std::vector<constructor_ptr>> constructors %type <std::vector<constructor_ptr>> constructors
%type <std::vector<parsed_type_ptr>> typeList %type <std::vector<parsed_type_ptr>> typeList
%type <binop> anyBinop
%type <definition_group> definitions %type <definition_group> definitions
%type <parsed_type_ptr> type nonArrowType typeListElement %type <parsed_type_ptr> type nonArrowType typeListElement
%type <ast_ptr> aInfix aEq aAdd aMul case let lambda app appBase %type <ast_ptr> aAdd aMul case let lambda app appBase
%type <definition_data_ptr> data %type <definition_data_ptr> data
%type <definition_defn_ptr> defn %type <definition_defn_ptr> defn
%type <branch_ptr> branch %type <branch_ptr> branch
@ -78,7 +73,7 @@ definitions
; ;
defn defn
: DEFN LID lowercaseParams EQUAL OCURLY aInfix CCURLY : DEFN LID lowercaseParams EQUAL OCURLY aAdd CCURLY
{ $$ = definition_defn_ptr( { $$ = definition_defn_ptr(
new definition_defn(std::move($2), std::move($3), std::move($6), @$)); } new definition_defn(std::move($2), std::move($3), std::move($6), @$)); }
; ;
@ -88,22 +83,6 @@ lowercaseParams
| lowercaseParams LID { $$ = std::move($1); $$.push_back(std::move($2)); } | lowercaseParams LID { $$ = std::move($1); $$.push_back(std::move($2)); }
; ;
aInfix
: aInfix BACKTICK LID BACKTICK aEq
{ $$ = ast_ptr(new ast_app(
ast_ptr(new ast_app(ast_ptr(new ast_lid(std::move($3))), std::move($1))), std::move($5))); }
| aInfix BACKTICK UID BACKTICK aEq
{ $$ = ast_ptr(new ast_app(
ast_ptr(new ast_app(ast_ptr(new ast_uid(std::move($3))), std::move($1))), std::move($5))); }
| aEq { $$ = std::move($1); }
;
aEq
: aAdd EQUALS aAdd { $$ = ast_ptr(new ast_binop(EQUALS, std::move($1), std::move($3), @$)); }
| aAdd LESS_EQUALS aAdd { $$ = ast_ptr(new ast_binop(LESS_EQUALS, std::move($1), std::move($3), @$)); }
| aAdd { $$ = std::move($1); }
;
aAdd aAdd
: aAdd PLUS aMul { $$ = ast_ptr(new ast_binop(PLUS, std::move($1), std::move($3), @$)); } : aAdd PLUS aMul { $$ = ast_ptr(new ast_binop(PLUS, std::move($1), std::move($3), @$)); }
| aAdd MINUS aMul { $$ = ast_ptr(new ast_binop(MINUS, std::move($1), std::move($3), @$)); } | aAdd MINUS aMul { $$ = ast_ptr(new ast_binop(MINUS, std::move($1), std::move($3), @$)); }
@ -113,7 +92,6 @@ aAdd
aMul aMul
: aMul TIMES app { $$ = ast_ptr(new ast_binop(TIMES, std::move($1), std::move($3), @$)); } : aMul TIMES app { $$ = ast_ptr(new ast_binop(TIMES, std::move($1), std::move($3), @$)); }
| aMul DIVIDE app { $$ = ast_ptr(new ast_binop(DIVIDE, std::move($1), std::move($3), @$)); } | aMul DIVIDE app { $$ = ast_ptr(new ast_binop(DIVIDE, std::move($1), std::move($3), @$)); }
| aMul MODULO app { $$ = ast_ptr(new ast_binop(MODULO, std::move($1), std::move($3), @$)); }
| app { $$ = std::move($1); } | app { $$ = std::move($1); }
; ;
@ -126,35 +104,24 @@ appBase
: INT { $$ = ast_ptr(new ast_int($1, @$)); } : INT { $$ = ast_ptr(new ast_int($1, @$)); }
| LID { $$ = ast_ptr(new ast_lid(std::move($1), @$)); } | LID { $$ = ast_ptr(new ast_lid(std::move($1), @$)); }
| UID { $$ = ast_ptr(new ast_uid(std::move($1), @$)); } | UID { $$ = ast_ptr(new ast_uid(std::move($1), @$)); }
| OPAREN aInfix CPAREN { $$ = std::move($2); } | OPAREN aAdd CPAREN { $$ = std::move($2); }
| OPAREN anyBinop CPAREN { $$ = ast_ptr(new ast_lid(op_name($2))); }
| case { $$ = std::move($1); } | case { $$ = std::move($1); }
| let { $$ = std::move($1); } | let { $$ = std::move($1); }
| lambda { $$ = std::move($1); } | lambda { $$ = std::move($1); }
; ;
anyBinop
: PLUS { $$ = PLUS; }
| MINUS { $$ = MINUS; }
| TIMES { $$ = TIMES; }
| DIVIDE { $$ = DIVIDE; }
| MODULO { $$ = MODULO; }
| EQUALS { $$ = EQUALS; }
| LESS_EQUALS { $$ = LESS_EQUALS; }
;
let let
: LET OCURLY definitions CCURLY IN OCURLY aInfix CCURLY : LET OCURLY definitions CCURLY IN OCURLY aAdd CCURLY
{ $$ = ast_ptr(new ast_let(std::move($3), std::move($7), @$)); } { $$ = ast_ptr(new ast_let(std::move($3), std::move($7), @$)); }
; ;
lambda lambda
: BACKSLASH lowercaseParams ARROW OCURLY aInfix CCURLY : BACKSLASH lowercaseParams ARROW OCURLY aAdd CCURLY
{ $$ = ast_ptr(new ast_lambda(std::move($2), std::move($5), @$)); } { $$ = ast_ptr(new ast_lambda(std::move($2), std::move($5), @$)); }
; ;
case case
: CASE aInfix OF OCURLY branches CCURLY : CASE aAdd OF OCURLY branches CCURLY
{ $$ = ast_ptr(new ast_case(std::move($2), std::move($5), @$)); } { $$ = ast_ptr(new ast_case(std::move($2), std::move($5), @$)); }
; ;
@ -164,7 +131,7 @@ branches
; ;
branch branch
: pattern ARROW OCURLY aInfix CCURLY : pattern ARROW OCURLY aAdd CCURLY
{ $$ = branch_ptr(new branch(std::move($1), std::move($4))); } { $$ = branch_ptr(new branch(std::move($1), std::move($4))); }
; ;

View File

@ -1,13 +1,9 @@
#include <bits/stdint-intn.h>
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <memory.h> #include <memory.h>
#include <stdio.h> #include <stdio.h>
#include "runtime.h" #include "runtime.h"
#define TOGGLE_MARK(n) ((uint64_t) n ^ ((uint64_t) 1 << 63))
#define IS_MARKED(n) ((((uint64_t) n) ^ ((uint64_t) n << 1)) & ((uint64_t) 1 << 63))
struct node_base* alloc_node() { struct node_base* alloc_node() {
struct node_base* new_node = malloc(sizeof(struct node_app)); struct node_base* new_node = malloc(sizeof(struct node_app));
new_node->gc_next = NULL; new_node->gc_next = NULL;
@ -25,7 +21,10 @@ struct node_app* alloc_app(struct node_base* l, struct node_base* r) {
} }
struct node_num* alloc_num(int32_t n) { struct node_num* alloc_num(int32_t n) {
return (struct node_num*) TOGGLE_MARK(n); struct node_num* node = (struct node_num*) alloc_node();
node->base.tag = NODE_NUM;
node->value = n;
return node;
} }
struct node_global* alloc_global(void (*f)(struct gmachine*), int32_t a) { struct node_global* alloc_global(void (*f)(struct gmachine*), int32_t a) {
@ -50,7 +49,7 @@ void free_node_direct(struct node_base* n) {
} }
void gc_visit_node(struct node_base* n) { void gc_visit_node(struct node_base* n) {
if(IS_MARKED(n) || n->gc_reachable) return; if(n->gc_reachable) return;
n->gc_reachable = 1; n->gc_reachable = 1;
if(n->tag == NODE_APP) { if(n->tag == NODE_APP) {
@ -170,7 +169,6 @@ void gmachine_split(struct gmachine* g, size_t n) {
} }
struct node_base* gmachine_track(struct gmachine* g, struct node_base* b) { struct node_base* gmachine_track(struct gmachine* g, struct node_base* b) {
if(IS_MARKED(b)) return b;
g->gc_node_count++; g->gc_node_count++;
b->gc_next = g->gc_nodes; b->gc_next = g->gc_nodes;
g->gc_nodes = b; g->gc_nodes = b;
@ -210,9 +208,7 @@ void unwind(struct gmachine* g) {
while(1) { while(1) {
struct node_base* peek = stack_peek(s, 0); struct node_base* peek = stack_peek(s, 0);
if(IS_MARKED(peek)) { if(peek->tag == NODE_APP) {
break;
} else if(peek->tag == NODE_APP) {
struct node_app* n = (struct node_app*) peek; struct node_app* n = (struct node_app*) peek;
stack_push(s, n->left); stack_push(s, n->left);
} else if(peek->tag == NODE_GLOBAL) { } else if(peek->tag == NODE_GLOBAL) {
@ -238,9 +234,7 @@ void unwind(struct gmachine* g) {
extern void f_main(struct gmachine* s); extern void f_main(struct gmachine* s);
void print_node(struct node_base* n) { void print_node(struct node_base* n) {
if(IS_MARKED(n)) { if(n->tag == NODE_APP) {
printf("%d", (int32_t) n);
} else if(n->tag == NODE_APP) {
struct node_app* app = (struct node_app*) n; struct node_app* app = (struct node_app*) n;
print_node(app->left); print_node(app->left);
putchar(' '); putchar(' ');
@ -252,6 +246,9 @@ void print_node(struct node_base* n) {
printf("(Global: %p)", global->function); printf("(Global: %p)", global->function);
} else if(n->tag == NODE_IND) { } else if(n->tag == NODE_IND) {
print_node(((struct node_ind*) n)->next); print_node(((struct node_ind*) n)->next);
} else if(n->tag == NODE_NUM) {
struct node_num* num = (struct node_num*) n;
printf("%d", num->value);
} }
} }

View File

@ -1,492 +0,0 @@
#ifndef yyHEADER_H
#define yyHEADER_H 1
#define yyIN_HEADER 1
#line 5 "scanner.hpp"
#line 7 "scanner.hpp"
#define YY_INT_ALIGNED short int
/* A lexical scanner generated by flex */
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 6
#define YY_FLEX_SUBMINOR_VERSION 4
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#ifndef SIZE_MAX
#define SIZE_MAX (~(size_t)0)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
/* begin standard C++ headers. */
/* TODO: this is always defined, so inline it */
#define yyconst const
#if defined(__GNUC__) && __GNUC__ >= 3
#define yynoreturn __attribute__((__noreturn__))
#else
#define yynoreturn
#endif
/* An opaque pointer. */
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
/* For convenience, these vars (plus the bison vars far below)
are macros in the reentrant scanner. */
#define yyin yyg->yyin_r
#define yyout yyg->yyout_r
#define yyextra yyg->yyextra_r
#define yyleng yyg->yyleng_r
#define yytext yyg->yytext_r
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
#define yy_flex_debug yyg->yy_flex_debug_r
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k.
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
* Ditto for the __ia64__ case accordingly.
*/
#define YY_BUF_SIZE 32768
#else
#define YY_BUF_SIZE 16384
#endif /* __ia64__ */
#endif
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
int yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
void yypop_buffer_state ( yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
void yyfree ( void * , yyscan_t yyscanner );
/* Begin user sect3 */
#define yywrap(yyscanner) (/*CONSTCOND*/1)
#define YY_SKIP_YYWRAP
#define yytext_ptr yytext_r
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
#define INITIAL 0
#endif
#ifndef YY_NO_UNISTD_H
/* Special case for "unistd.h", since it is non-ANSI. We include it way
* down here because we want the user's section 1 to have been scanned first.
* The user has a chance to override it with an option.
*/
#include <unistd.h>
#endif
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
#endif
int yylex_init (yyscan_t* scanner);
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int yylex_destroy ( yyscan_t yyscanner );
int yyget_debug ( yyscan_t yyscanner );
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
FILE *yyget_in ( yyscan_t yyscanner );
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
FILE *yyget_out ( yyscan_t yyscanner );
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
int yyget_leng ( yyscan_t yyscanner );
char *yyget_text ( yyscan_t yyscanner );
int yyget_lineno ( yyscan_t yyscanner );
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
int yyget_column ( yyscan_t yyscanner );
void yyset_column ( int _column_no , yyscan_t yyscanner );
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap ( yyscan_t yyscanner );
#else
extern int yywrap ( yyscan_t yyscanner );
#endif
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
#endif
#ifndef YY_NO_INPUT
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k */
#define YY_READ_BUF_SIZE 16384
#else
#define YY_READ_BUF_SIZE 8192
#endif /* __ia64__ */
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int yylex (yyscan_t yyscanner);
#define YY_DECL int yylex (yyscan_t yyscanner)
#endif /* !YY_DECL */
/* yy_get_previous_state - get the state just before the EOB char was reached */
#undef YY_NEW_FILE
#undef YY_FLUSH_BUFFER
#undef yy_set_bol
#undef yy_new_buffer
#undef yy_set_interactive
#undef YY_DO_BEFORE_ACTION
#ifdef YY_DECL_IS_OURS
#undef YY_DECL_IS_OURS
#undef YY_DECL
#endif
#ifndef yy_create_buffer_ALREADY_DEFINED
#undef yy_create_buffer
#endif
#ifndef yy_delete_buffer_ALREADY_DEFINED
#undef yy_delete_buffer
#endif
#ifndef yy_scan_buffer_ALREADY_DEFINED
#undef yy_scan_buffer
#endif
#ifndef yy_scan_string_ALREADY_DEFINED
#undef yy_scan_string
#endif
#ifndef yy_scan_bytes_ALREADY_DEFINED
#undef yy_scan_bytes
#endif
#ifndef yy_init_buffer_ALREADY_DEFINED
#undef yy_init_buffer
#endif
#ifndef yy_flush_buffer_ALREADY_DEFINED
#undef yy_flush_buffer
#endif
#ifndef yy_load_buffer_state_ALREADY_DEFINED
#undef yy_load_buffer_state
#endif
#ifndef yy_switch_to_buffer_ALREADY_DEFINED
#undef yy_switch_to_buffer
#endif
#ifndef yypush_buffer_state_ALREADY_DEFINED
#undef yypush_buffer_state
#endif
#ifndef yypop_buffer_state_ALREADY_DEFINED
#undef yypop_buffer_state
#endif
#ifndef yyensure_buffer_stack_ALREADY_DEFINED
#undef yyensure_buffer_stack
#endif
#ifndef yylex_ALREADY_DEFINED
#undef yylex
#endif
#ifndef yyrestart_ALREADY_DEFINED
#undef yyrestart
#endif
#ifndef yylex_init_ALREADY_DEFINED
#undef yylex_init
#endif
#ifndef yylex_init_extra_ALREADY_DEFINED
#undef yylex_init_extra
#endif
#ifndef yylex_destroy_ALREADY_DEFINED
#undef yylex_destroy
#endif
#ifndef yyget_debug_ALREADY_DEFINED
#undef yyget_debug
#endif
#ifndef yyset_debug_ALREADY_DEFINED
#undef yyset_debug
#endif
#ifndef yyget_extra_ALREADY_DEFINED
#undef yyget_extra
#endif
#ifndef yyset_extra_ALREADY_DEFINED
#undef yyset_extra
#endif
#ifndef yyget_in_ALREADY_DEFINED
#undef yyget_in
#endif
#ifndef yyset_in_ALREADY_DEFINED
#undef yyset_in
#endif
#ifndef yyget_out_ALREADY_DEFINED
#undef yyget_out
#endif
#ifndef yyset_out_ALREADY_DEFINED
#undef yyset_out
#endif
#ifndef yyget_leng_ALREADY_DEFINED
#undef yyget_leng
#endif
#ifndef yyget_text_ALREADY_DEFINED
#undef yyget_text
#endif
#ifndef yyget_lineno_ALREADY_DEFINED
#undef yyget_lineno
#endif
#ifndef yyset_lineno_ALREADY_DEFINED
#undef yyset_lineno
#endif
#ifndef yyget_column_ALREADY_DEFINED
#undef yyget_column
#endif
#ifndef yyset_column_ALREADY_DEFINED
#undef yyset_column
#endif
#ifndef yywrap_ALREADY_DEFINED
#undef yywrap
#endif
#ifndef yyget_lval_ALREADY_DEFINED
#undef yyget_lval
#endif
#ifndef yyset_lval_ALREADY_DEFINED
#undef yyset_lval
#endif
#ifndef yyget_lloc_ALREADY_DEFINED
#undef yyget_lloc
#endif
#ifndef yyset_lloc_ALREADY_DEFINED
#undef yyset_lloc
#endif
#ifndef yyalloc_ALREADY_DEFINED
#undef yyalloc
#endif
#ifndef yyrealloc_ALREADY_DEFINED
#undef yyrealloc
#endif
#ifndef yyfree_ALREADY_DEFINED
#undef yyfree
#endif
#ifndef yytext_ALREADY_DEFINED
#undef yytext
#endif
#ifndef yyleng_ALREADY_DEFINED
#undef yyleng
#endif
#ifndef yyin_ALREADY_DEFINED
#undef yyin
#endif
#ifndef yyout_ALREADY_DEFINED
#undef yyout
#endif
#ifndef yy_flex_debug_ALREADY_DEFINED
#undef yy_flex_debug
#endif
#ifndef yylineno_ALREADY_DEFINED
#undef yylineno
#endif
#ifndef yytables_fload_ALREADY_DEFINED
#undef yytables_fload
#endif
#ifndef yytables_destroy_ALREADY_DEFINED
#undef yytables_destroy
#endif
#ifndef yyTABLES_NAME_ALREADY_DEFINED
#undef yyTABLES_NAME
#endif
#line 49 "/home/vanilla/projects/blog-static/code/compiler/13/scanner.l"
#line 490 "scanner.hpp"
#undef yyIN_HEADER
#endif /* yyHEADER_H */

View File

@ -24,10 +24,6 @@
\* { return yy::parser::make_TIMES(LOC); } \* { return yy::parser::make_TIMES(LOC); }
- { return yy::parser::make_MINUS(LOC); } - { return yy::parser::make_MINUS(LOC); }
\/ { return yy::parser::make_DIVIDE(LOC); } \/ { return yy::parser::make_DIVIDE(LOC); }
% { return yy::parser::make_MODULO(LOC); }
== { return yy::parser::make_EQUALS(LOC); }
\<= { return yy::parser::make_LESS_EQUALS(LOC); }
` { return yy::parser::make_BACKTICK(LOC); }
[0-9]+ { return yy::parser::make_INT(atoi(yytext), LOC); } [0-9]+ { return yy::parser::make_INT(atoi(yytext), LOC); }
defn { return yy::parser::make_DEFN(LOC); } defn { return yy::parser::make_DEFN(LOC); }
data { return yy::parser::make_DATA(LOC); } data { return yy::parser::make_DATA(LOC); }

View File

@ -38,10 +38,6 @@ void type_base::print(const type_mgr& mgr, std::ostream& to) const {
to << name; to << name;
} }
void type_internal::print(const type_mgr& mgr, std::ostream& to) const {
to << "!" << name;
}
void type_arr::print(const type_mgr& mgr, std::ostream& to) const { void type_arr::print(const type_mgr& mgr, std::ostream& to) const {
type_var* var; type_var* var;
bool print_parenths = dynamic_cast<type_arr*>(mgr.resolve(left, var).get()) != nullptr; bool print_parenths = dynamic_cast<type_arr*>(mgr.resolve(left, var).get()) != nullptr;
@ -128,8 +124,7 @@ void type_mgr::unify(type_ptr l, type_ptr r, const std::optional<yy::location>&
} else if((lid = dynamic_cast<type_base*>(l.get())) && } else if((lid = dynamic_cast<type_base*>(l.get())) &&
(rid = dynamic_cast<type_base*>(r.get()))) { (rid = dynamic_cast<type_base*>(r.get()))) {
if(lid->name == rid->name && if(lid->name == rid->name &&
lid->arity == rid->arity && lid->arity == rid->arity)
lid->is_internal() == rid->is_internal())
return; return;
} else if((lapp = dynamic_cast<type_app*>(l.get())) && } else if((lapp = dynamic_cast<type_app*>(l.get())) &&
(rapp = dynamic_cast<type_app*>(r.get()))) { (rapp = dynamic_cast<type_app*>(r.get()))) {

View File

@ -46,17 +46,6 @@ struct type_base : public type {
: name(std::move(n)), arity(a) {} : name(std::move(n)), arity(a) {}
void print(const type_mgr& mgr, std::ostream& to) const; void print(const type_mgr& mgr, std::ostream& to) const;
virtual bool is_internal() const { return false; }
};
struct type_internal : public type_base {
type_internal(std::string n, int32_t a = 0)
: type_base(std::move(n), a) {}
void print(const type_mgr& mgr, std::ostream& to) const;
bool is_internal() const { return true; }
}; };
struct type_data : public type_base { struct type_data : public type_base {