#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){} 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)); } } 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){ listing.emplace_back(Instruction::Type::enter); assert(expr.scope.type==ScopeDef::Type::direct); 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: listing.emplace_back(Instruction::Type::pushscope,new ScopeDef(expr.scope)); break; } } Assembly::Assembly(const StatementList &stl){ codegen(stl); } ostream& operator<<(ostream &os,const Assembly &as){ for(const Assembly::Instruction &ins : as.listing){ switch(ins.type){ case Assembly::Instruction::Type::pushnil: os<<"pushnil\n"; break; case Assembly::Instruction::Type::pushnum: os<<"pushnum "<