diff options
Diffstat (limited to 'functions.cpp')
-rw-r--r-- | functions.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/functions.cpp b/functions.cpp new file mode 100644 index 0000000..4795c93 --- /dev/null +++ b/functions.cpp @@ -0,0 +1,310 @@ +#include <iostream> +#include <fstream> +#include <unordered_map> +#include <vector> +#include <string> +#include <functional> +#include <unistd.h> +#include <fcntl.h> + +#include "runtime.h" + +using namespace std; + +extern int g_argc; +extern char **g_argv; + +#define BUILTIN_GUARD_STACKSIZE(nm,sz) {if(S.size()<(sz))throw string("Builtin '" nm "' needs " #sz " stack item")+(sz==1?"":"s");} + +//please extern this shit with const! +unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stackitem>&)>> builtins={ + {"+",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("+",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(!a.isstr&&!b.isstr){ + S.emplace_back(a.intval+b.intval); + return; + } + if(!a.isstr){ + a.strval=to_string(a.intval); + a.isstr=true; + } + if(!b.isstr){ + b.strval=to_string(b.intval); + b.isstr=true; + } + S.emplace_back(a.strval+b.strval); + }}, + {"-",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("-",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr||b.isstr)throw string("Builtin '-' cannot accept a string argument"); + S.emplace_back(a.intval-b.intval); + }}, + {"*",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("*",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr||b.isstr)throw string("Builtin '*' cannot accept a string argument"); + S.emplace_back(a.intval*b.intval); + }}, + {"/",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("/",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr||b.isstr)throw string("Builtin '/' cannot accept a string argument"); + S.emplace_back(a.intval/b.intval); + }}, + {"%",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("%",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr||b.isstr){ + cerr<<"modding "; + if(a.isstr)cerr<<'"'<<a.strval<<'"'; else cerr<<a.intval; + cerr<<" and "; + if(b.isstr)cerr<<'"'<<b.strval<<'"'; else cerr<<b.intval; + cerr<<endl; + } + if(a.isstr||b.isstr)throw string("Builtin '%' cannot accept a string argument"); + S.emplace_back(a.intval%b.intval); + }}, + {"^",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("^",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr||b.isstr)throw string("Builtin '^' cannot accept a string argument"); + S.emplace_back((int)pow(a.intval,b.intval)); + }}, + {"!",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("!",1) + Stackitem v=move(S.back()); S.pop_back(); + if(v.isstr)S.emplace_back(!v.strval.size()); + else S.emplace_back(!v.intval); + }}, + {"=",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("=",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + S.emplace_back(a==b); + }}, + {"<",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("<",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr&&b.isstr)S.emplace_back(a.strval<b.strval); + else if(!a.isstr&&!b.isstr)S.emplace_back(a.intval<b.intval); + else if(a.isstr)S.emplace_back(a.strval<to_string(b.intval)); + else S.emplace_back(to_string(a.intval)<b.strval); + }}, + {">",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE(">",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + if(a.isstr&&b.isstr)S.emplace_back(a.strval>b.strval); + else if(!a.isstr&&!b.isstr)S.emplace_back(a.intval>b.intval); + else if(a.isstr)S.emplace_back(a.strval>to_string(b.intval)); + else S.emplace_back(to_string(a.intval)>b.strval); + }}, + {"print",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("print",1) + Stackitem v=move(S.back()); S.pop_back(); + if(v.isstr)cout<<v.strval<<flush; + else cout<<v.intval<<flush; + }}, + {"lf",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("lf",0) + cout<<endl; + }}, + {"getline",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("getline",0) + string line; + getline(cin,line); + if(!cin)S.emplace_back(-1); + else S.emplace_back(line); + }}, + {"getc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("getc",0) + char c=cin.get(); + if(!cin)S.emplace_back(-1); + else S.emplace_back(string(1,c)); + }}, + {"fprint",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("fprint",2) + Stackitem file=move(S.back()); S.pop_back(); + Stackitem v=move(S.back()); S.pop_back(); + if(file.isstr)throw string("Second argument to 'fprint' not a number"); + if(v.isstr)write(file.intval,v.strval.data(),v.strval.size()); + else { + string s=to_string(v.intval); + write(file.intval,s.data(),s.size()); + } + }}, + {"flf",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("flf",1) + Stackitem file=move(S.back()); S.pop_back(); + if(file.isstr)throw string("Argument to 'flf' not a number"); + write(file.intval,"\n",1); + }}, + {"fgetc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("fgetc",1) + Stackitem file=move(S.back()); S.pop_back(); + if(file.isstr)throw string("Argument to 'fgetc' not a number"); + char c; + int ret=read(file.intval,&c,1); + if(ret==-1)perror("read"); + if(ret<=0)S.emplace_back(-1); + else S.emplace_back(string(1,c)); + }}, + {"fopen",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("fopen",2) + Stackitem mode=move(S.back()); S.pop_back(); + Stackitem fname=move(S.back()); S.pop_back(); + if(!fname.isstr)throw string("First argument to 'fopen' not a string"); + if(!mode.isstr)throw string("Second argument to 'fopen' not a string"); + int oflag=0; + if(mode.strval.find('r')!=string::npos)oflag|=O_RDONLY; + if(mode.strval.find('w')!=string::npos){ + if(oflag&O_RDONLY)oflag=(oflag&~O_RDONLY)|O_RDWR; + else oflag|=O_WRONLY; + } + if(mode.strval.find('a')!=string::npos)oflag|=O_APPEND; + if(mode.strval.find('x')!=string::npos)oflag|=O_EXCL|O_CREAT; + if(oflag==0)oflag=O_RDONLY; + int ret=open(fname.strval.c_str(),oflag); + if(ret<0)perror("open"); + S.emplace_back(ret); + }}, + {"argc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("argc",0) + S.emplace_back(g_argc); + }}, + {"argvget",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("argvget",1) + Stackitem idx=move(S.back()); S.pop_back(); + if(idx.isstr)throw string("Argument to 'argvget' not a number"); + if(idx.intval<0||idx.intval>=g_argc)throw string("Argument to 'argvget' out of bounds"); + S.emplace_back(g_argv[idx.intval]); + }}, + {"dup",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("dup",1) + S.push_back(S.back()); + }}, + {"pop",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("pop",1) + S.pop_back(); + }}, + {"swap",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("swap",2) + Stackitem b=move(S.back()); S.pop_back(); + Stackitem a=move(S.back()); S.pop_back(); + S.push_back(b); + S.push_back(a); + }}, + {"store",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("store",2) + Stackitem name=move(S.back()); S.pop_back(); + if(!name.isstr)throw string("Second argument to 'store' not a string"); + variables[name.strval]=move(S.back()); + S.pop_back(); + }}, + {"get",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("get",1) + Stackitem name=move(S.back()); S.pop_back(); + if(!name.isstr)throw string("Argument to 'get' not a string"); + S.push_back(variables[name.strval]); + }}, + //leaves variable with value 0 + {"swapoutvar",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("swapoutvar",1) + Stackitem name=move(S.back()); S.pop_back(); + if(!name.isstr)throw string("Second argument to 'swapoutvar' not a string"); + S.push_back(move(variables[name.strval])); + variables[name.strval].intval=0; + }}, + //positive n: roll OFF top to bottom; negative n: roll off bottom ONTO top + {"roll",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("roll",1) + Stackitem ns=move(S.back()); S.pop_back(); + if(ns.isstr)throw string("Argument to 'roll' not a number"); + int n=ns.intval; + if(S.size()<2)return; + bool negative=n<0; + if(negative)n=-n; + n%=S.size(); + if(n==0)return; + if(negative){ + vector<Stackitem> tempstore; + tempstore.reserve(n); + int ssz=S.size(); + for(int i=ssz-n;i<ssz;i++)tempstore.push_back(move(S[i])); + S.erase(S.end()-n,S.end()); + S.insert(S.begin(),n,Stackitem()); + for(int i=0;i<n;i++)S[i]=move(tempstore[i]); + } else { + //cerr<<"rolling back n="<<n<<endl; + vector<Stackitem> tempstore; + tempstore.reserve(n); + for(int i=0;i<n;i++)tempstore.push_back(move(S[i])); + S.erase(S.begin(),S.begin()+n); + for(int i=0;i<n;i++)S.push_back(move(tempstore[i])); + } + }}, + //leaves the string on the stack + {"stridx",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("stridx",2) + Stackitem idx=move(S.back()); S.pop_back(); + const Stackitem &str=S.back(); + if(!str.isstr)throw string("First argument to 'stridx' not a string"); + if(idx.isstr)throw string("Second argument to 'stridx' not a number"); + if(idx.intval<0||idx.intval>=(int)str.strval.size())throw string("Index argument to 'stridx' out of range"); + S.emplace_back(string(1,str.strval[idx.intval])); + }}, + //leaves the string on the stack + {"strlen",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("strlen",1) + const Stackitem &str=S.back(); + if(!str.isstr)throw string("Argument to 'strlen' not a string"); + S.emplace_back(str.strval.size()); + }}, + //leaves the string on the stack + {"substr",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("substr",3) + const Stackitem to=move(S.back()); S.pop_back(); + const Stackitem from=move(S.back()); S.pop_back(); + const Stackitem &str=S.back(); + if(!str.isstr)throw string("First argument to 'substr' not a string"); + if(from.isstr)throw string("Second argument to 'substr' not a number"); + if(to.isstr)throw string("Third argument to 'substr' not a number"); + S.emplace_back(str.strval.substr(from.intval,to.intval-from.intval)); + }}, + {"chr",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("chr",1) + Stackitem ascii=move(S.back()); S.pop_back(); + if(ascii.isstr)throw string("Argument to 'chr' not a number"); + S.emplace_back(string(1,ascii.intval)); + }}, + {"ord",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("ord",1) + if(!S.back().isstr)throw string("Argument to 'ord' not a string"); + S.back().isstr=false; + S.back().intval=(int)S.back().strval[0]; + S.back().strval=""; + }}, + {"stackdump",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("stackdump",0) + cerr<<"STACKDUMP: "; + for(const Stackitem &si : S){ + if(si.isstr)cerr<<'"'<<si.strval<<"\" "; + else cerr<<si.intval<<' '; + } + cerr<<endl; + }}, + {"exit",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("exit",0) + exit(0); + }}, +}; +#undef BUILTIN_GUARD_STACKSIZE |