forked from gfwilliams/tiny-js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscriptMain.cpp
317 lines (262 loc) · 8.6 KB
/
scriptMain.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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
* File: scriptMain.cpp
* Author: ghernan
*
* Script engine main file. Contains 'evaluate' function, which runs an script
* contained in a string.
*
* Created on December 4, 2016, 10:31 PM
*/
#include "ascript_pch.hpp"
#include "scriptMain.h"
#include "jsParser.h"
#include "mvmCodegen.h"
#include "TinyJS_Functions.h"
#include "TinyJS_MathFunctions.h"
#include "mvmFunctions.h"
#include "semanticCheck.h"
#include "asObjects.h"
#include "ScriptException.h"
#include "utils.h"
#include "modules.h"
using namespace std;
// Functions forward declarations.
//////////////////////////////////////////
StringVector parseArgumentList(CScriptToken token);
/**
* Script evaluation function. Runs a script, and returns its result.
*
* @param script Script code, in a C string.
* @param globals Global symbols
* @return
*/
ASValue evaluate (const char* script, Ref<JSObject> globals)
{
return evaluate (script, globals, "", NULL);
}
/**
* Script evaluation function. Runs a script, and returns its result.
*
* @param script Script code, in a C string.
* @param globals Global symbols
* @param scriptPath
* @param parentEC
* @return
*/
ASValue evaluate (const char* script,
Ref<JSObject> globals,
const std::string& scriptPath,
ExecutionContext* parentEC)
{
CScriptToken token (script);
//Parse
auto parseResult = parseScript(token.next());
auto ast = parseResult.ast;
//Semantic check
semanticCheck(ast);
//Code generation.
CodeMap cMap;
const Ref<MvmRoutine> code = scriptCodegen(ast, &cMap);
//Execution
return evaluate (code, &cMap, globals, scriptPath, parentEC);
}
/**
* Evaluates a compiled script.
* @param code
* @param codeMap
* @param globals
* @return
*/
ASValue evaluate (Ref<MvmRoutine> code,
const CodeMap* codeMap,
Ref<JSObject> globals,
const std::string& scriptPath,
ExecutionContext* parentEC)
{
try
{
string path;
if (scriptPath.empty())
path = getCurrentDirectory();
else
path = normalizePath(scriptPath);
if (parentEC == NULL)
{
Modules mods;
ExecutionContext newEC (path, &mods);
mods.modules[path] = globals->value();
newEC.stack.push_back(globals->value());
return mvmExecRoutine(code, &newEC, 1);
}
else
{
ExecutionContext newEC (path, parentEC->modules);
newEC.stack.push_back(globals->value());
return mvmExecRoutine(code, &newEC, 1);
}
}
catch (const RuntimeError& e)
{
ScriptPosition pos;
if (codeMap != NULL)
pos = codeMap->get(e.Position);
errorAt(pos, "%s", e.what());
return jsNull(); //Not executed
}
}
/**
* Creates the default global scope
* @return
*/
Ref<JSObject> createDefaultGlobals()
{
auto globals = JSObject::create();
registerMvmFunctions(globals);
registerFunctions(globals);
registerMathFunctions(globals);
return globals;
}
/**
* Adds a new native function. This version uses a javascript declaration of
* the function name to get its name and parameters.
* @param szFunctionHeader Javascript function header definition, which includes the
* function name and parameters.
* @param pFn Pointer to native function.
* @param scope Scope object to which the function will be added.
* @param isConst To specify if the function shall be added as a constant or as
* a variable.
* @return A new Javascript function object
*/
Ref<JSFunction> addNative (const std::string& szFunctionHeader,
JSNativeFn pFn,
Ref<JSObject> container,
bool isConst)
{
CScriptToken token(szFunctionHeader.c_str());
token = token.next();
token = token.match(LEX_R_FUNCTION);
string funcName = token.text();
token = token.match(LEX_ID);
//Next dots, read in previous objects
while (token.type() == '.')
{
token = token.match('.');
ASValue child = container->readField(funcName);
// if it doesn't exist or it is not an object, make an object class
if (child.getType() != VT_OBJECT)
{
child = JSObject::create()->value();
container->writeField(funcName, child, isConst);
}
container = child.staticCast<JSObject>();
funcName = token.text();
token = token.match(LEX_ID);
}
Ref<JSFunction> function = JSFunction::createNative(funcName,
parseArgumentList(token),
pFn);
container->writeField(funcName, function->value(), isConst);
return function;
}
/**
* Adds a new native function to a variable map.
* @param szFunctionHeader
* @param pFn
* @param varMap
* @return
*/
Ref<JSFunction> addNative (const std::string& szFunctionHeader,
JSNativeFn pFn,
VarMap& varMap)
{
CScriptToken token(szFunctionHeader.c_str());
token = token.next();
token = token.match(LEX_R_FUNCTION);
string funcName = token.text();
token = token.match(LEX_ID);
Ref<JSObject> container;
Ref<JSFunction> function = JSFunction::createNative(funcName,
parseArgumentList(token),
pFn);
varMap.checkedVarWrite(funcName, function->value(), true);
return function;
}
/**
* Parses a function argument list.
* @note Used by 'addNative' function
* @param token
* @return A vector with argument names.
*/
StringVector parseArgumentList(CScriptToken token)
{
//TODO: It is a copy & paste from the function of the same name in 'jsParser.cpp'
//But the other version uses a 'AstFunction', not a 'StringVector'
token = token.match('(');
StringVector arguments;
while (token.type() != ')')
{
const string name = token.text();
token = token.match(LEX_ID);
arguments.push_back(name);
if (token.type() != ')')
token = token.match(',');
}
token.match(')');
return arguments;
}
/**
* Adds a native function with no arguments
* @param szName Function name
* @param pFn Pointer to native function
* @param scope Scope object to which the function will be added.
* @return A new Javascript function object
*/
Ref<JSFunction> addNative0 (const std::string& szName,
JSNativeFn pFn,
Ref<JSObject> container)
{
Ref<JSFunction> function = JSFunction::createNative(szName, StringVector(), pFn);
container->writeField(szName, function->value(), true);
return function;
}
/**
* Adds a native function with one argument
* @param szName Function name
* @param p1 First parameter name
* @param pFn Pointer to native function
* @param scope Scope object to which the function will be added.
* @return A new Javascript function object
*/
Ref<JSFunction> addNative1 (const std::string& szName,
const std::string& p1,
JSNativeFn pFn,
Ref<JSObject> container)
{
StringVector arguments;
arguments.push_back(p1);
Ref<JSFunction> function = JSFunction::createNative(szName, arguments, pFn);
container->writeField(szName, function->value(), true);
return function;
}
/**
* Adds a native function with two arguments
* @param szName Function name
* @param p1 First parameter name
* @param p1 Second parameter name
* @param pFn Pointer to native function
* @param scope Scope object to which the function will be added.
* @return A new Javascript function object
*/
Ref<JSFunction> addNative2 (const std::string& szName,
const std::string& p1,
const std::string& p2,
JSNativeFn pFn,
Ref<JSObject> container)
{
StringVector arguments;
arguments.push_back(p1);
arguments.push_back(p2);
Ref<JSFunction> function = JSFunction::createNative(szName, arguments, pFn);
container->writeField(szName, function->value(), true);
return function;
}