#include #include #include "evaluate.h" using namespace std; ExecutionError::ExecutionError(const string &what_arg) :runtime_error(what_arg){} ExecutionError::ExecutionError(const char *what_arg) :runtime_error(what_arg){} CompilationError::CompilationError(const string &what_arg) :runtime_error(what_arg){} CompilationError::CompilationError(const char *what_arg) :runtime_error(what_arg){} CompilationError::CompilationError(Site site,const string &what_arg) :runtime_error(site.filename+":"+to_string(site.lnum)+":"+to_string(site.linex)+": "+what_arg){} Value::Value() :type(Type::nil){} Value::Value(double numval) :type(Type::number),numval(numval){} Value::Value(const string &strval) :type(Type::string),strval(strval){} Value::Value(ScopeVal *scopeval) :type(Type::scope),scopeval(scopeval){} Value::Value(Type type,Assembly *asmval):type(type),asmval(asmval){ if(type!=Type::lazy&&type!=Type::function){ throw runtime_error("Value(type,asmval) called with invalid type "+to_string((int)type)); } } Value::Value(const Value &other):type(other.type),numval(other.numval),strval(other.strval){ if(other.scopeval){ scopeval=new ScopeVal(*other.scopeval); } } Value::Value(Value &&other):type(other.type),numval(other.numval), strval(other.strval),scopeval(other.scopeval){ if(other.scopeval){ other.type=Type::nil; other.scopeval=nullptr; } } Value::~Value(){ if(scopeval)delete scopeval; } ScopeVal::ScopeVal(const ScopeDef &scopeDef) :scopeDef(scopeDef){} namespace A { struct CollItem{ int count; void (*deleter)(void*); }; template static void generic_deleter(void *p){ delete (T*)p; } unordered_map collection; template T* ref(T *p){ auto it=collection.find((void*)p); if(it==collection.end()){ collection.emplace((void*)p,(CollItem){1,generic_deleter}); } else { it->second.count++; } return p; } template void unref(T *p){ auto it=collection.find(p); assert(it!=collection.end()); if(it->second.count==1){ if(it->second.deleter!=generic_deleter){ throw runtime_error("Unref'd pointer type not the same as the ref'd version!"); } it->second.deleter(p); collection.erase(it); } else { it->second.count--; } } void unref_all(){ for(const pair &p : collection){ p.second.deleter(p.first); } } } Assembly::Instruction::Instruction(Type type):type(type){ if(type==Type::pushnum||type==Type::pushstr||type==Type::pushscope|| type==Type::create||type==Type::store||type==Type::load||type==Type::call){ throw runtime_error("Instruction(type) called with invalid type "+to_string((int)type)); } } Assembly::Instruction::Instruction(Type type,double num):type(type),num(num){ if(type!=Type::pushnum){ throw runtime_error("Instruction(type,num) called with invalid type "+to_string((int)type)); } } Assembly::Instruction::Instruction(Type type,const string &arg):type(type){ if(type==Type::pushstr){ str=arg; } else if(type==Type::create||type==Type::store||type==Type::load){ name=arg; } else { throw runtime_error("Instruction(type,string) called with invalid type "+to_string((int)type)); } } Assembly::Instruction::Instruction(Type type,ScopeDef *scope):type(type),scope(scope){ if(type!=Type::pushscope){ throw runtime_error("Instruction(type,scope) called with invalid type "+to_string((int)type)); } } Assembly::Instruction::Instruction(Type type,int nargs):type(type),nargs(nargs){ if(type!=Type::call){ throw runtime_error("Instruction(type,nargs) called with invalid type "+to_string((int)type)); } } Assembly::Instruction::Instruction(Type type,Assembly *asmval):type(type),asmval(asmval){ if(type!=Type::pushfunc){ throw runtime_error("Instruction(type,asmval) called with invalid type "+to_string((int)type)); } } Assembly::Instruction::Instruction(const Instruction &other) :type(other.type),num(other.num),str(other.str),name(other.name),nargs(other.nargs){ if(other.scope){ scope=new ScopeDef(*other.scope); } if(other.asmval){ asmval=new Assembly(*other.asmval); } } Assembly::Instruction::Instruction(Instruction &&other) :type(other.type),num(other.num),str(other.str), scope(other.scope),name(other.name),nargs(other.nargs){ if(other.scope){ other.type=Type::pushnil; other.scope=nullptr; } if(other.asmval){ other.type=Type::pushnil; other.asmval=nullptr; } } Assembly::Instruction::~Instruction(){ if(scope)delete scope; } void Assembly::codegen(const StatementList &stl){ for(const Statement &stmt : stl){ codegen(stmt); } } void Assembly::codegen(const Statement &stmt){ switch(stmt.type){ case Statement::Type::create: codegen(stmt.expr); listing.emplace_back(Instruction::Type::create,stmt.dstvar); break; case Statement::Type::assign: codegen(stmt.expr); listing.emplace_back(Instruction::Type::store,stmt.dstvar); break; case Statement::Type::expression: codegen(stmt.expr); listing.emplace_back(Instruction::Type::pop); break; } } void Assembly::codegen(const Expression &expr){ switch(expr.type){ case Expression::Type::binop: codegen(expr.args[0]); codegen(expr.args[1]); if(expr.name=="+")listing.emplace_back(Instruction::Type::add); else if(expr.name=="-")listing.emplace_back(Instruction::Type::sub); else if(expr.name=="*")listing.emplace_back(Instruction::Type::mul); else if(expr.name=="/")listing.emplace_back(Instruction::Type::div); else if(expr.name=="%")listing.emplace_back(Instruction::Type::mod); else throw runtime_error("Unknown binop name '"+expr.name+"'"); break; case Expression::Type::unop: throw runtime_error("No unary operators known?"); case Expression::Type::call: case Expression::Type::dive: if(expr.name=="nil"){ if(expr.args.size()!=0||expr.type==Expression::Type::dive){ if(expr.type==Expression::Type::call)throw CompilationError(expr.site,"Cannot call nil"); else throw CompilationError(expr.site,"Cannot dive into nil"); } listing.emplace_back(Instruction::Type::pushnil); break; } listing.emplace_back(Instruction::Type::load,expr.name); for(const Expression &arg : expr.args){ codegen(arg); } if(expr.args.size()!=0){ listing.emplace_back(Instruction::Type::call,(int)expr.args.size()); } if(expr.type==Expression::Type::dive){ assert(expr.scope.type==ScopeDef::Type::direct); listing.emplace_back(Instruction::Type::enter); codegen(expr.scope.body); listing.emplace_back(Instruction::Type::leave); } break; case Expression::Type::number: listing.emplace_back(Instruction::Type::pushnum,expr.numval); break; case Expression::Type::string: listing.emplace_back(Instruction::Type::pushstr,expr.strval); break; case Expression::Type::scope: switch(expr.scope.type){ case ScopeDef::Type::direct: assert(expr.scope.args.size()==0); listing.emplace_back(Instruction::Type::newscope); listing.emplace_back(Instruction::Type::enter); codegen(expr.scope.body); listing.emplace_back(Instruction::Type::leave); break; case ScopeDef::Type::lazy: throw runtime_error("Lazy scopes not implemented"); case ScopeDef::Type::function: listing.emplace_back(Instruction::Type::pushfunc,new Assembly(expr.scope)); break; } break; case Expression::Type::cond: throw runtime_error("Conditions not implemented"); } } Assembly::Assembly(const StatementList &stl){ codegen(stl); } Assembly::Assembly(const ScopeDef &scopeDef){ for(int i=scopeDef.args.size()-1;i>=0;i--){ listing.emplace_back(Instruction::Type::create,scopeDef.args[i]); } codegen(scopeDef.body); } ostream& operator<<(ostream &os,const Assembly &as){ static int depth=0; depth++; for(const Assembly::Instruction &ins : as.listing){ os<