-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterpreter.cpp
170 lines (147 loc) · 3.92 KB
/
interpreter.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "interpreter.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <memory>
Interpreter::Interpreter(tokenizerBase& tok_, bool terminator_, obj_ptr main_):
tok{tok_}, endAtTerminator{terminator_}, main{main_}, curr_slot_name{} {
// thanks to the upperScope functionality this is only need in main
main->addIntoSlot("method", std::make_shared<Function<func_ptr>>(builtins::createMethod));
main->addIntoSlot("if", std::make_shared<Function<func_ptr>>(builtins::cond));
main->addIntoSlot("while", std::make_shared<Function<func_ptr>>(builtins::while_));
main->addIntoSlot("for", std::make_shared<Function<func_ptr>>(builtins::for_));
curr_scope=main;
tok.prepare();
token currToken;
do {
currToken=tok.nextToken();
terminator=false;
// curr_scope is a method
if(curr_scope->callable) {
// arguments borderd by ()
if(currToken==token::openArguments) {
tok.flush();
Arguments args=Arguments(tok);
curr_scope=(*curr_scope)(function_scope, args);
currToken=tok.nextToken();
}else{
// read til you find end or lower priority
Arguments args;
if(currToken==token::symbol || currToken==token::openArguments) {
std::string symbol=tok.flush();
while(symbolPriority(symbol)>curr_scope_priority) {
if(currToken==token::symbol)
args.addToken(currToken, symbol);
else
args.addTilClose(tok);
currToken=tok.nextToken();
if(currToken!=token::symbol && currToken!=token::openArguments) break;
symbol=tok.flush();
}
}
args.addToken(token::terminator, "");
args.restart();
curr_scope=(*curr_scope)(function_scope, args);
}
}
switch(currToken) {
case token::symbol:
processSymbol();
break;
case token::terminator:
case token::endOfBlock:
resetScope();
break;
case token::openArguments:
runBlock();
break;
default:
std::cerr<<"Unknown token."<<(int)currToken<<std::endl;
}
} while(!tok.eof() && currToken!=token::endOfBlock &&
!(endAtTerminator && terminator));
}
void Interpreter::processSymbol() {
std::string s=tok.flush();
if(s.empty())
return;
if(s=="True" || s=="False") {
auto new_obj=builtins::new_bool(s[0]=='T', curr_scope);
curr_scope->addIntoSlot(s, new_obj);
curr_scope=curr_scope->getSlot(s);
return;
}
bool no=true;
for(auto&& c:s) {
if(!('0'<=c && c<='9')) {
no=false;
break;
}
}
if(no) {
auto new_no=builtins::new_number(stoi(s), curr_scope);
curr_scope->addIntoSlot(s, new_no);
curr_scope=curr_scope->getSlot(s);
return;
}
obj_ptr next_slot;
bool assign=false;
// if it's direct assignment or the slot does not exist
if(s=="=" || s==":=") {
assign=true;
s=curr_slot_name;
curr_scope=main;
}else {
next_slot=curr_scope->getSlot(s);
if(next_slot==nullptr) {
token nextTok=tok.nextToken();
std::string op=tok.flush();
if(!(nextTok==token::symbol && op==":="))
throw std::logic_error("Slot "+s+" not defined.");
assign=true;
}
}
// either assing
if(assign) {
Interpreter expr(tok, true, curr_scope);
obj_ptr copy=(expr.lastScope())->clone();
main->addIntoSlot(s, copy);
curr_scope=copy;
resetScope();
}else{
// or move to next symbol
// set callable data
if(next_slot->callable) {
function_scope=curr_scope;
curr_scope_priority=symbolPriority(s);
}
// the next command can be simple assignment
if(curr_scope==main) {
curr_slot_name=s;
}
curr_scope=next_slot;
}
}
void Interpreter::runBlock() {
Arguments block(tok);
curr_scope=block.execute(curr_scope)->clone();
}
void Interpreter::resetScope() {
old_scope=curr_scope;
curr_scope=main;
terminator=true;
}
using namespace std;
int main(int argc, char * * argv) {
std::ifstream iff;
if(argc>1) {
std::vector<std::string> args{argv+1, argv+argc};
iff= ifstream{ args[0] };
}else
iff= ifstream{ "tests/testfile.io" };
processStream in(iff);
tokenizer tok(in);
Interpreter run(tok, false);
return 0;
}