summaryrefslogtreecommitdiff
path: root/functions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'functions.cpp')
-rw-r--r--functions.cpp310
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