OpenShot Audio Library | OpenShotAudio: juce_Javascript.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0

Loading...
Searching...
No Matches
juce_Javascript.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26#define JUCE_JS_OPERATORS(X) \
27 X(semicolon, ";") X(dot, ".") X(comma, ",") \
28 X(openParen, "(") X(closeParen, ")") X(openBrace, "{") X(closeBrace, "}") \
29 X(openBracket, "[") X(closeBracket, "]") X(colon, ":") X(question, "?") \
30 X(typeEquals, "===") X(equals, "==") X(assign, "=") \
31 X(typeNotEquals, "!==") X(notEquals, "!=") X(logicalNot, "!") \
32 X(plusEquals, "+=") X(plusplus, "++") X(plus, "+") \
33 X(minusEquals, "-=") X(minusminus, "--") X(minus, "-") \
34 X(timesEquals, "*=") X(times, "*") X(divideEquals, "/=") X(divide, "/") \
35 X(moduloEquals, "%=") X(modulo, "%") X(xorEquals, "^=") X(bitwiseXor, "^") \
36 X(andEquals, "&=") X(logicalAnd, "&&") X(bitwiseAnd, "&") \
37 X(orEquals, "|=") X(logicalOr, "||") X(bitwiseOr, "|") \
38 X(leftShiftEquals, "<<=") X(lessThanOrEqual, "<=") X(leftShift, "<<") X(lessThan, "<") \
39 X(rightShiftUnsigned, ">>>") X(rightShiftEquals, ">>=") X(rightShift, ">>") X(greaterThanOrEqual, ">=") X(greaterThan, ">")
40
41#define JUCE_JS_KEYWORDS(X) \
42 X(var, "var") X(if_, "if") X(else_, "else") X(do_, "do") X(null_, "null") \
43 X(while_, "while") X(for_, "for") X(break_, "break") X(continue_, "continue") X(undefined, "undefined") \
44 X(function, "function") X(return_, "return") X(true_, "true") X(false_, "false") X(new_, "new") \
45 X(typeof_, "typeof")
46
47namespace TokenTypes
48{
49 #define JUCE_DECLARE_JS_TOKEN(name, str) static const char* const name = str;
50 JUCE_JS_KEYWORDS (JUCE_DECLARE_JS_TOKEN)
51 JUCE_JS_OPERATORS (JUCE_DECLARE_JS_TOKEN)
52 JUCE_DECLARE_JS_TOKEN (eof, "$eof")
53 JUCE_DECLARE_JS_TOKEN (literal, "$literal")
54 JUCE_DECLARE_JS_TOKEN (identifier, "$identifier")
55}
56
57JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702)
58
59//==============================================================================
60struct JavascriptEngine::RootObject final : public DynamicObject
61{
62 RootObject()
63 {
64 setMethod ("exec", exec);
65 setMethod ("eval", eval);
66 setMethod ("trace", trace);
67 setMethod ("charToInt", charToInt);
68 setMethod ("parseInt", IntegerClass::parseInt);
69 setMethod ("typeof", typeof_internal);
70 setMethod ("parseFloat", parseFloat);
71 }
72
73 Time timeout;
74
75 using Args = const var::NativeFunctionArgs&;
76 using TokenType = const char*;
77
78 void execute (const String& code)
79 {
80 ExpressionTreeBuilder tb (code);
81 std::unique_ptr<BlockStatement> (tb.parseStatementList())->perform (Scope ({}, *this, *this), nullptr);
82 }
83
84 var evaluate (const String& code)
85 {
86 ExpressionTreeBuilder tb (code);
87 return ExpPtr (tb.parseExpression())->getResult (Scope ({}, *this, *this));
88 }
89
90 //==============================================================================
91 static bool areTypeEqual (const var& a, const var& b)
92 {
93 return a.hasSameTypeAs (b) && isFunction (a) == isFunction (b)
94 && (((a.isUndefined() || a.isVoid()) && (b.isUndefined() || b.isVoid())) || a == b);
95 }
96
97 static String getTokenName (TokenType t) { return t[0] == '$' ? String (t + 1) : ("'" + String (t) + "'"); }
98 static bool isFunction (const var& v) noexcept { return dynamic_cast<FunctionObject*> (v.getObject()) != nullptr; }
99 static bool isNumeric (const var& v) noexcept { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool(); }
100 static bool isNumericOrUndefined (const var& v) noexcept { return isNumeric (v) || v.isUndefined(); }
101 static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s.initialSectionContainingOnly ("01234567"), 8); return b.toInt64(); }
102 static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; }
103 static var* getPropertyPointer (DynamicObject& o, const Identifier& i) noexcept { return o.getProperties().getVarPointer (i); }
104
105 //==============================================================================
106 struct CodeLocation
107 {
108 CodeLocation (const String& code) noexcept : program (code), location (program.getCharPointer()) {}
109 CodeLocation (const CodeLocation& other) noexcept : program (other.program), location (other.location) {}
110
111 void throwError (const String& message) const
112 {
113 int col = 1, line = 1;
114
115 for (auto i = program.getCharPointer(); i < location && ! i.isEmpty(); ++i)
116 {
117 ++col;
118 if (*i == '\n') { col = 1; ++line; }
119 }
120
121 throw "Line " + String (line) + ", column " + String (col) + " : " + message;
122 }
123
124 String program;
125 String::CharPointerType location;
126 };
127
128 //==============================================================================
129 struct Scope
130 {
131 Scope (const Scope* p, ReferenceCountedObjectPtr<RootObject> rt, DynamicObject::Ptr scp) noexcept
132 : parent (p), root (std::move (rt)),
133 scope (std::move (scp)) {}
134
135 const Scope* const parent;
136 ReferenceCountedObjectPtr<RootObject> root;
137 DynamicObject::Ptr scope;
138
139 var findFunctionCall (const CodeLocation& location, const var& targetObject, const Identifier& functionName) const
140 {
141 if (auto* o = targetObject.getDynamicObject())
142 {
143 if (auto* prop = getPropertyPointer (*o, functionName))
144 return *prop;
145
146 for (auto* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
147 p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
148 {
149 if (auto* prop = getPropertyPointer (*p, functionName))
150 return *prop;
151 }
152
153 // if there's a class with an overridden DynamicObject::hasMethod, this avoids an error
154 if (o->hasMethod (functionName))
155 return {};
156 }
157
158 if (targetObject.isString())
159 if (auto* m = findRootClassProperty (StringClass::getClassName(), functionName))
160 return *m;
161
162 if (targetObject.isArray())
163 if (auto* m = findRootClassProperty (ArrayClass::getClassName(), functionName))
164 return *m;
165
166 if (auto* m = findRootClassProperty (ObjectClass::getClassName(), functionName))
167 return *m;
168
169 location.throwError ("Unknown function '" + functionName.toString() + "'");
170 return {};
171 }
172
173 var* findRootClassProperty (const Identifier& className, const Identifier& propName) const
174 {
175 if (auto* cls = root->getProperty (className).getDynamicObject())
176 return getPropertyPointer (*cls, propName);
177
178 return nullptr;
179 }
180
181 var findSymbolInParentScopes (const Identifier& name) const
182 {
183 if (auto v = getPropertyPointer (*scope, name))
184 return *v;
185
186 return parent != nullptr ? parent->findSymbolInParentScopes (name)
187 : var::undefined();
188 }
189
190 bool findAndInvokeMethod (const Identifier& function, const var::NativeFunctionArgs& args, var& result) const
191 {
192 auto* target = args.thisObject.getDynamicObject();
193
194 if (target == nullptr || target == scope.get())
195 {
196 if (auto* m = getPropertyPointer (*scope, function))
197 {
198 if (auto fo = dynamic_cast<FunctionObject*> (m->getObject()))
199 {
200 result = fo->invoke (*this, args);
201 return true;
202 }
203 }
204 }
205
206 const auto& props = scope->getProperties();
207
208 for (int i = 0; i < props.size(); ++i)
209 if (auto* o = props.getValueAt (i).getDynamicObject())
210 if (Scope (this, *root, *o).findAndInvokeMethod (function, args, result))
211 return true;
212
213 return false;
214 }
215
216 bool invokeMethod (const var& m, const var::NativeFunctionArgs& args, var& result) const
217 {
218 if (isFunction (m))
219 {
220 auto* target = args.thisObject.getDynamicObject();
221
222 if (target == nullptr || target == scope.get())
223 {
224 if (auto fo = dynamic_cast<FunctionObject*> (m.getObject()))
225 {
226 result = fo->invoke (*this, args);
227 return true;
228 }
229 }
230 }
231
232 return false;
233 }
234
235 void checkTimeOut (const CodeLocation& location) const
236 {
237 if (Time::getCurrentTime() > root->timeout)
238 location.throwError (root->timeout == Time() ? "Interrupted" : "Execution timed-out");
239 }
240
241 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Scope)
242 };
243
244 //==============================================================================
245 struct Statement
246 {
247 Statement (const CodeLocation& l) noexcept : location (l) {}
248 virtual ~Statement() = default;
249
250 enum ResultCode { ok = 0, returnWasHit, breakWasHit, continueWasHit };
251 virtual ResultCode perform (const Scope&, var*) const { return ok; }
252
253 CodeLocation location;
254 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Statement)
255 };
256
257 struct Expression : public Statement
258 {
259 Expression (const CodeLocation& l) noexcept : Statement (l) {}
260
261 virtual var getResult (const Scope&) const { return var::undefined(); }
262 virtual void assign (const Scope&, const var&) const { location.throwError ("Cannot assign to this expression!"); }
263
264 ResultCode perform (const Scope& s, var*) const override { getResult (s); return ok; }
265 };
266
267 using ExpPtr = std::unique_ptr<Expression>;
268
269 struct BlockStatement final : public Statement
270 {
271 BlockStatement (const CodeLocation& l) noexcept : Statement (l) {}
272
273 ResultCode perform (const Scope& s, var* returnedValue) const override
274 {
275 for (auto* statement : statements)
276 if (auto r = statement->perform (s, returnedValue))
277 return r;
278
279 return ok;
280 }
281
282 OwnedArray<Statement> statements;
283 };
284
285 struct IfStatement final : public Statement
286 {
287 IfStatement (const CodeLocation& l) noexcept : Statement (l) {}
288
289 ResultCode perform (const Scope& s, var* returnedValue) const override
290 {
291 return (condition->getResult (s) ? trueBranch : falseBranch)->perform (s, returnedValue);
292 }
293
294 ExpPtr condition;
295 std::unique_ptr<Statement> trueBranch, falseBranch;
296 };
297
298 struct VarStatement final : public Statement
299 {
300 VarStatement (const CodeLocation& l) noexcept : Statement (l) {}
301
302 ResultCode perform (const Scope& s, var*) const override
303 {
304 s.scope->setProperty (name, initialiser->getResult (s));
305 return ok;
306 }
307
308 Identifier name;
309 ExpPtr initialiser;
310 };
311
312 struct LoopStatement final : public Statement
313 {
314 LoopStatement (const CodeLocation& l, bool isDo) noexcept : Statement (l), isDoLoop (isDo) {}
315
316 ResultCode perform (const Scope& s, var* returnedValue) const override
317 {
318 initialiser->perform (s, nullptr);
319
320 while (isDoLoop || condition->getResult (s))
321 {
322 s.checkTimeOut (location);
323 auto r = body->perform (s, returnedValue);
324
325 if (r == returnWasHit) return r;
326 if (r == breakWasHit) break;
327
328 iterator->perform (s, nullptr);
329
330 if (isDoLoop && r != continueWasHit && ! condition->getResult (s))
331 break;
332 }
333
334 return ok;
335 }
336
337 std::unique_ptr<Statement> initialiser, iterator, body;
338 ExpPtr condition;
339 bool isDoLoop;
340 };
341
342 struct ReturnStatement final : public Statement
343 {
344 ReturnStatement (const CodeLocation& l, Expression* v) noexcept : Statement (l), returnValue (v) {}
345
346 ResultCode perform (const Scope& s, var* ret) const override
347 {
348 if (ret != nullptr) *ret = returnValue->getResult (s);
349 return returnWasHit;
350 }
351
352 ExpPtr returnValue;
353 };
354
355 struct BreakStatement final : public Statement
356 {
357 BreakStatement (const CodeLocation& l) noexcept : Statement (l) {}
358 ResultCode perform (const Scope&, var*) const override { return breakWasHit; }
359 };
360
361 struct ContinueStatement final : public Statement
362 {
363 ContinueStatement (const CodeLocation& l) noexcept : Statement (l) {}
364 ResultCode perform (const Scope&, var*) const override { return continueWasHit; }
365 };
366
367 struct LiteralValue final : public Expression
368 {
369 LiteralValue (const CodeLocation& l, const var& v) noexcept : Expression (l), value (v) {}
370 var getResult (const Scope&) const override { return value; }
371 var value;
372 };
373
374 struct UnqualifiedName final : public Expression
375 {
376 UnqualifiedName (const CodeLocation& l, const Identifier& n) noexcept : Expression (l), name (n) {}
377
378 var getResult (const Scope& s) const override { return s.findSymbolInParentScopes (name); }
379
380 void assign (const Scope& s, const var& newValue) const override
381 {
382 if (auto* v = getPropertyPointer (*s.scope, name))
383 *v = newValue;
384 else
385 s.root->setProperty (name, newValue);
386 }
387
388 Identifier name;
389 };
390
391 struct DotOperator final : public Expression
392 {
393 DotOperator (const CodeLocation& l, ExpPtr& p, const Identifier& c) noexcept : Expression (l), parent (p.release()), child (c) {}
394
395 var getResult (const Scope& s) const override
396 {
397 auto p = parent->getResult (s);
398 static const Identifier lengthID ("length");
399
400 if (child == lengthID)
401 {
402 if (auto* array = p.getArray()) return array->size();
403 if (p.isString()) return p.toString().length();
404 }
405
406 if (auto* o = p.getDynamicObject())
407 if (auto* v = getPropertyPointer (*o, child))
408 return *v;
409
410 return var::undefined();
411 }
412
413 void assign (const Scope& s, const var& newValue) const override
414 {
415 if (auto* o = parent->getResult (s).getDynamicObject())
416 o->setProperty (child, newValue);
417 else
418 Expression::assign (s, newValue);
419 }
420
421 ExpPtr parent;
422 Identifier child;
423 };
424
425 struct ArraySubscript final : public Expression
426 {
427 ArraySubscript (const CodeLocation& l) noexcept : Expression (l) {}
428
429 var getResult (const Scope& s) const override
430 {
431 auto arrayVar = object->getResult (s); // must stay alive for the scope of this method
432 auto key = index->getResult (s);
433
434 if (const auto* array = arrayVar.getArray())
435 if (key.isInt() || key.isInt64() || key.isDouble())
436 return (*array) [static_cast<int> (key)];
437
438 if (auto* o = arrayVar.getDynamicObject())
439 if (key.isString())
440 if (auto* v = getPropertyPointer (*o, Identifier (key)))
441 return *v;
442
443 return var::undefined();
444 }
445
446 void assign (const Scope& s, const var& newValue) const override
447 {
448 auto arrayVar = object->getResult (s); // must stay alive for the scope of this method
449 auto key = index->getResult (s);
450
451 if (auto* array = arrayVar.getArray())
452 {
453 if (key.isInt() || key.isInt64() || key.isDouble())
454 {
455 const int i = key;
456 while (array->size() < i)
457 array->add (var::undefined());
458
459 array->set (i, newValue);
460 return;
461 }
462 }
463
464 if (auto* o = arrayVar.getDynamicObject())
465 {
466 if (key.isString())
467 {
468 o->setProperty (Identifier (key), newValue);
469 return;
470 }
471 }
472
473 Expression::assign (s, newValue);
474 }
475
476 ExpPtr object, index;
477 };
478
479 struct BinaryOperatorBase : public Expression
480 {
481 BinaryOperatorBase (const CodeLocation& l, ExpPtr& a, ExpPtr& b, TokenType op) noexcept
482 : Expression (l), lhs (a.release()), rhs (b.release()), operation (op) {}
483
484 ExpPtr lhs, rhs;
485 TokenType operation;
486 };
487
488 struct BinaryOperator : public BinaryOperatorBase
489 {
490 BinaryOperator (const CodeLocation& l, ExpPtr& a, ExpPtr& b, TokenType op) noexcept
491 : BinaryOperatorBase (l, a, b, op) {}
492
493 virtual var getWithUndefinedArg() const { return var::undefined(); }
494 virtual var getWithDoubles (double, double) const { return throwError ("Double"); }
495 virtual var getWithInts (int64, int64) const { return throwError ("Integer"); }
496 virtual var getWithArrayOrObject (const var& a, const var&) const { return throwError (a.isArray() ? "Array" : "Object"); }
497 virtual var getWithStrings (const String&, const String&) const { return throwError ("String"); }
498
499 var getResult (const Scope& s) const override
500 {
501 var a (lhs->getResult (s)), b (rhs->getResult (s));
502
503 if ((a.isUndefined() || a.isVoid()) && (b.isUndefined() || b.isVoid()))
504 return getWithUndefinedArg();
505
506 if (isNumericOrUndefined (a) && isNumericOrUndefined (b))
507 return (a.isDouble() || b.isDouble()) ? getWithDoubles (a, b) : getWithInts (a, b);
508
509 if (a.isArray() || a.isObject())
510 return getWithArrayOrObject (a, b);
511
512 return getWithStrings (a.toString(), b.toString());
513 }
514
515 var throwError (const char* typeName) const
516 { location.throwError (getTokenName (operation) + " is not allowed on the " + typeName + " type"); return {}; }
517 };
518
519 struct EqualsOp final : public BinaryOperator
520 {
521 EqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::equals) {}
522 var getWithUndefinedArg() const override { return true; }
523 var getWithDoubles (double a, double b) const override { return exactlyEqual (a, b); }
524 var getWithInts (int64 a, int64 b) const override { return a == b; }
525 var getWithStrings (const String& a, const String& b) const override { return a == b; }
526 var getWithArrayOrObject (const var& a, const var& b) const override { return a == b; }
527 };
528
529 struct NotEqualsOp final : public BinaryOperator
530 {
531 NotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::notEquals) {}
532 var getWithUndefinedArg() const override { return false; }
533 var getWithDoubles (double a, double b) const override { return ! exactlyEqual (a, b); }
534 var getWithInts (int64 a, int64 b) const override { return a != b; }
535 var getWithStrings (const String& a, const String& b) const override { return a != b; }
536 var getWithArrayOrObject (const var& a, const var& b) const override { return a != b; }
537 };
538
539 struct LessThanOp final : public BinaryOperator
540 {
541 LessThanOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::lessThan) {}
542 var getWithDoubles (double a, double b) const override { return a < b; }
543 var getWithInts (int64 a, int64 b) const override { return a < b; }
544 var getWithStrings (const String& a, const String& b) const override { return a < b; }
545 };
546
547 struct LessThanOrEqualOp final : public BinaryOperator
548 {
549 LessThanOrEqualOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::lessThanOrEqual) {}
550 var getWithDoubles (double a, double b) const override { return a <= b; }
551 var getWithInts (int64 a, int64 b) const override { return a <= b; }
552 var getWithStrings (const String& a, const String& b) const override { return a <= b; }
553 };
554
555 struct GreaterThanOp final : public BinaryOperator
556 {
557 GreaterThanOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::greaterThan) {}
558 var getWithDoubles (double a, double b) const override { return a > b; }
559 var getWithInts (int64 a, int64 b) const override { return a > b; }
560 var getWithStrings (const String& a, const String& b) const override { return a > b; }
561 };
562
563 struct GreaterThanOrEqualOp final : public BinaryOperator
564 {
565 GreaterThanOrEqualOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::greaterThanOrEqual) {}
566 var getWithDoubles (double a, double b) const override { return a >= b; }
567 var getWithInts (int64 a, int64 b) const override { return a >= b; }
568 var getWithStrings (const String& a, const String& b) const override { return a >= b; }
569 };
570
571 struct AdditionOp final : public BinaryOperator
572 {
573 AdditionOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::plus) {}
574 var getWithDoubles (double a, double b) const override { return a + b; }
575 var getWithInts (int64 a, int64 b) const override { return a + b; }
576 var getWithStrings (const String& a, const String& b) const override { return a + b; }
577 };
578
579 struct SubtractionOp final : public BinaryOperator
580 {
581 SubtractionOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::minus) {}
582 var getWithDoubles (double a, double b) const override { return a - b; }
583 var getWithInts (int64 a, int64 b) const override { return a - b; }
584 };
585
586 struct MultiplyOp final : public BinaryOperator
587 {
588 MultiplyOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::times) {}
589 var getWithDoubles (double a, double b) const override { return a * b; }
590 var getWithInts (int64 a, int64 b) const override { return a * b; }
591 };
592
593 struct DivideOp final : public BinaryOperator
594 {
595 DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
596 var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits<double>::infinity() : a / b; }
597 var getWithInts (int64 a, int64 b) const override { return b != 0 ? var ((double) a / (double) b) : var (std::numeric_limits<double>::infinity()); }
598 };
599
600 struct ModuloOp final : public BinaryOperator
601 {
602 ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {}
603 var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits<double>::infinity() : fmod (a, b); }
604 var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); }
605 };
606
607 struct BitwiseOrOp final : public BinaryOperator
608 {
609 BitwiseOrOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseOr) {}
610 var getWithInts (int64 a, int64 b) const override { return a | b; }
611 };
612
613 struct BitwiseAndOp final : public BinaryOperator
614 {
615 BitwiseAndOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseAnd) {}
616 var getWithInts (int64 a, int64 b) const override { return a & b; }
617 };
618
619 struct BitwiseXorOp final : public BinaryOperator
620 {
621 BitwiseXorOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseXor) {}
622 var getWithInts (int64 a, int64 b) const override { return a ^ b; }
623 };
624
625 struct LeftShiftOp final : public BinaryOperator
626 {
627 LeftShiftOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::leftShift) {}
628 var getWithInts (int64 a, int64 b) const override { return ((int) a) << (int) b; }
629 };
630
631 struct RightShiftOp final : public BinaryOperator
632 {
633 RightShiftOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::rightShift) {}
634 var getWithInts (int64 a, int64 b) const override { return ((int) a) >> (int) b; }
635 };
636
637 struct RightShiftUnsignedOp final : public BinaryOperator
638 {
639 RightShiftUnsignedOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::rightShiftUnsigned) {}
640 var getWithInts (int64 a, int64 b) const override { return (int) (((uint32) a) >> (int) b); }
641 };
642
643 struct LogicalAndOp final : public BinaryOperatorBase
644 {
645 LogicalAndOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::logicalAnd) {}
646 var getResult (const Scope& s) const override { return lhs->getResult (s) && rhs->getResult (s); }
647 };
648
649 struct LogicalOrOp final : public BinaryOperatorBase
650 {
651 LogicalOrOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::logicalOr) {}
652 var getResult (const Scope& s) const override { return lhs->getResult (s) || rhs->getResult (s); }
653 };
654
655 struct TypeEqualsOp final : public BinaryOperatorBase
656 {
657 TypeEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::typeEquals) {}
658 var getResult (const Scope& s) const override { return areTypeEqual (lhs->getResult (s), rhs->getResult (s)); }
659 };
660
661 struct TypeNotEqualsOp final : public BinaryOperatorBase
662 {
663 TypeNotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::typeNotEquals) {}
664 var getResult (const Scope& s) const override { return ! areTypeEqual (lhs->getResult (s), rhs->getResult (s)); }
665 };
666
667 struct ConditionalOp final : public Expression
668 {
669 ConditionalOp (const CodeLocation& l) noexcept : Expression (l) {}
670
671 var getResult (const Scope& s) const override { return (condition->getResult (s) ? trueBranch : falseBranch)->getResult (s); }
672 void assign (const Scope& s, const var& v) const override { (condition->getResult (s) ? trueBranch : falseBranch)->assign (s, v); }
673
674 ExpPtr condition, trueBranch, falseBranch;
675 };
676
677 struct Assignment final : public Expression
678 {
679 Assignment (const CodeLocation& l, ExpPtr& dest, ExpPtr& source) noexcept : Expression (l), target (dest.release()), newValue (source.release()) {}
680
681 var getResult (const Scope& s) const override
682 {
683 auto value = newValue->getResult (s);
684 target->assign (s, value);
685 return value;
686 }
687
688 ExpPtr target, newValue;
689 };
690
691 struct SelfAssignment : public Expression
692 {
693 SelfAssignment (const CodeLocation& l, Expression* dest, Expression* source) noexcept
694 : Expression (l), target (dest), newValue (source) {}
695
696 var getResult (const Scope& s) const override
697 {
698 auto value = newValue->getResult (s);
699 target->assign (s, value);
700 return value;
701 }
702
703 Expression* target; // Careful! this pointer aliases a sub-term of newValue!
704 ExpPtr newValue;
705 TokenType op;
706 };
707
708 struct PostAssignment final : public SelfAssignment
709 {
710 PostAssignment (const CodeLocation& l, Expression* dest, Expression* source) noexcept : SelfAssignment (l, dest, source) {}
711
712 var getResult (const Scope& s) const override
713 {
714 auto oldValue = target->getResult (s);
715 target->assign (s, newValue->getResult (s));
716 return oldValue;
717 }
718 };
719
720 struct FunctionCall : public Expression
721 {
722 FunctionCall (const CodeLocation& l) noexcept : Expression (l) {}
723
724 var getResult (const Scope& s) const override
725 {
726 if (auto* dot = dynamic_cast<DotOperator*> (object.get()))
727 {
728 auto thisObject = dot->parent->getResult (s);
729 return invokeFunction (s, s.findFunctionCall (location, thisObject, dot->child), thisObject);
730 }
731
732 auto function = object->getResult (s);
733 return invokeFunction (s, function, var (s.scope.get()));
734 }
735
736 var invokeFunction (const Scope& s, const var& function, const var& thisObject) const
737 {
738 s.checkTimeOut (location);
739 Array<var> argVars;
740
741 for (auto* a : arguments)
742 argVars.add (a->getResult (s));
743
744 const var::NativeFunctionArgs args (thisObject, argVars.begin(), argVars.size());
745
746 if (var::NativeFunction nativeFunction = function.getNativeFunction())
747 return nativeFunction (args);
748
749 if (auto* fo = dynamic_cast<FunctionObject*> (function.getObject()))
750 return fo->invoke (s, args);
751
752 if (auto* dot = dynamic_cast<DotOperator*> (object.get()))
753 if (auto* o = thisObject.getDynamicObject())
754 if (o->hasMethod (dot->child)) // allow an overridden DynamicObject::invokeMethod to accept a method call.
755 return o->invokeMethod (dot->child, args);
756
757 location.throwError ("This expression is not a function!"); return {};
758 }
759
760 ExpPtr object;
761 OwnedArray<Expression> arguments;
762 };
763
764 struct NewOperator final : public FunctionCall
765 {
766 NewOperator (const CodeLocation& l) noexcept : FunctionCall (l) {}
767
768 var getResult (const Scope& s) const override
769 {
770 var classOrFunc = object->getResult (s);
771 const bool isFunc = isFunction (classOrFunc);
772
773 if (! (isFunc || classOrFunc.getDynamicObject() != nullptr))
774 return var::undefined();
775
776 DynamicObject::Ptr newObject (new DynamicObject());
777
778 if (isFunc)
779 invokeFunction (s, classOrFunc, newObject.get());
780 else
781 newObject->setProperty (getPrototypeIdentifier(), classOrFunc);
782
783 return newObject.get();
784 }
785 };
786
787 struct ObjectDeclaration final : public Expression
788 {
789 ObjectDeclaration (const CodeLocation& l) noexcept : Expression (l) {}
790
791 var getResult (const Scope& s) const override
792 {
793 DynamicObject::Ptr newObject (new DynamicObject());
794
795 for (int i = 0; i < names.size(); ++i)
796 newObject->setProperty (names.getUnchecked (i), initialisers.getUnchecked (i)->getResult (s));
797
798 return newObject.get();
799 }
800
801 Array<Identifier> names;
802 OwnedArray<Expression> initialisers;
803 };
804
805 struct ArrayDeclaration final : public Expression
806 {
807 ArrayDeclaration (const CodeLocation& l) noexcept : Expression (l) {}
808
809 var getResult (const Scope& s) const override
810 {
811 Array<var> a;
812
813 for (int i = 0; i < values.size(); ++i)
814 a.add (values.getUnchecked (i)->getResult (s));
815
816 // std::move() needed here for older compilers
817 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move")
818 return std::move (a);
819 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
820 }
821
822 OwnedArray<Expression> values;
823 };
824
825 //==============================================================================
826 struct FunctionObject final : public DynamicObject
827 {
828 FunctionObject() noexcept {}
829
830 FunctionObject (const FunctionObject& other) : DynamicObject(), functionCode (other.functionCode)
831 {
832 ExpressionTreeBuilder tb (functionCode);
833 tb.parseFunctionParamsAndBody (*this);
834 }
835
836 std::unique_ptr<DynamicObject> clone() const override { return std::make_unique<FunctionObject> (*this); }
837
838 void writeAsJSON (OutputStream& out, const JSON::FormatOptions&) override
839 {
840 out << "function " << functionCode;
841 }
842
843 var invoke (const Scope& s, const var::NativeFunctionArgs& args) const
844 {
845 DynamicObject::Ptr functionRoot (new DynamicObject());
846
847 static const Identifier thisIdent ("this");
848 functionRoot->setProperty (thisIdent, args.thisObject);
849
850 for (int i = 0; i < parameters.size(); ++i)
851 functionRoot->setProperty (parameters.getReference (i),
852 i < args.numArguments ? args.arguments[i] : var::undefined());
853
854 var result;
855 body->perform (Scope (&s, s.root, functionRoot), &result);
856 return result;
857 }
858
859 String functionCode;
860 Array<Identifier> parameters;
861 std::unique_ptr<Statement> body;
862 };
863
864 //==============================================================================
865 struct TokenIterator
866 {
867 TokenIterator (const String& code) : location (code), p (code.getCharPointer()) { skip(); }
868
869 void skip()
870 {
871 skipWhitespaceAndComments();
872 location.location = p;
873 currentType = matchNextToken();
874 }
875
876 void match (TokenType expected)
877 {
878 if (currentType != expected)
879 location.throwError ("Found " + getTokenName (currentType) + " when expecting " + getTokenName (expected));
880
881 skip();
882 }
883
884 bool matchIf (TokenType expected) { if (currentType == expected) { skip(); return true; } return false; }
885 bool matchesAny (TokenType t1, TokenType t2) const { return currentType == t1 || currentType == t2; }
886 bool matchesAny (TokenType t1, TokenType t2, TokenType t3) const { return matchesAny (t1, t2) || currentType == t3; }
887
888 CodeLocation location;
889 TokenType currentType;
890 var currentValue;
891
892 private:
893 String::CharPointerType p;
894
895 static bool isIdentifierStart (juce_wchar c) noexcept { return CharacterFunctions::isLetter (c) || c == '_'; }
896 static bool isIdentifierBody (juce_wchar c) noexcept { return CharacterFunctions::isLetterOrDigit (c) || c == '_'; }
897
898 TokenType matchNextToken()
899 {
900 if (isIdentifierStart (*p))
901 {
902 auto end = p;
903 while (isIdentifierBody (*++end)) {}
904
905 auto len = (size_t) (end - p);
906 #define JUCE_JS_COMPARE_KEYWORD(name, str) if (len == sizeof (str) - 1 && matchToken (TokenTypes::name, len)) return TokenTypes::name;
907 JUCE_JS_KEYWORDS (JUCE_JS_COMPARE_KEYWORD)
908
909 currentValue = String (p, end); p = end;
910 return TokenTypes::identifier;
911 }
912
913 if (p.isDigit())
914 {
915 if (parseHexLiteral() || parseFloatLiteral() || parseOctalLiteral() || parseDecimalLiteral())
916 return TokenTypes::literal;
917
918 location.throwError ("Syntax error in numeric constant");
919 }
920
921 if (parseStringLiteral (*p) || (*p == '.' && parseFloatLiteral()))
922 return TokenTypes::literal;
923
924 #define JUCE_JS_COMPARE_OPERATOR(name, str) if (matchToken (TokenTypes::name, sizeof (str) - 1)) return TokenTypes::name;
925 JUCE_JS_OPERATORS (JUCE_JS_COMPARE_OPERATOR)
926
927 if (! p.isEmpty())
928 location.throwError ("Unexpected character '" + String::charToString (*p) + "' in source");
929
930 return TokenTypes::eof;
931 }
932
933 bool matchToken (TokenType name, size_t len) noexcept
934 {
935 if (p.compareUpTo (CharPointer_ASCII (name), (int) len) != 0) return false;
936 p += (int) len; return true;
937 }
938
939 void skipWhitespaceAndComments()
940 {
941 for (;;)
942 {
943 p.incrementToEndOfWhitespace();
944
945 if (*p == '/')
946 {
947 auto c2 = p[1];
948
949 if (c2 == '/') { p = CharacterFunctions::find (p, (juce_wchar) '\n'); continue; }
950
951 if (c2 == '*')
952 {
953 location.location = p;
954 p = CharacterFunctions::find (p + 2, CharPointer_ASCII ("*/"));
955 if (p.isEmpty()) location.throwError ("Unterminated '/*' comment");
956 p += 2; continue;
957 }
958 }
959
960 break;
961 }
962 }
963
964 bool parseStringLiteral (juce_wchar quoteType)
965 {
966 if (quoteType != '"' && quoteType != '\'')
967 return false;
968
969 auto r = JSON::parseQuotedString (p, currentValue);
970 if (r.failed()) location.throwError (r.getErrorMessage());
971 return true;
972 }
973
974 bool parseHexLiteral()
975 {
976 if (*p != '0' || (p[1] != 'x' && p[1] != 'X')) return false;
977
978 auto t = ++p;
979 int64 v = CharacterFunctions::getHexDigitValue (*++t);
980 if (v < 0) return false;
981
982 for (;;)
983 {
984 auto digit = CharacterFunctions::getHexDigitValue (*++t);
985 if (digit < 0) break;
986 v = v * 16 + digit;
987 }
988
989 currentValue = v; p = t;
990 return true;
991 }
992
993 bool parseFloatLiteral()
994 {
995 int numDigits = 0;
996 auto t = p;
997 while (t.isDigit()) { ++t; ++numDigits; }
998
999 const bool hasPoint = (*t == '.');
1000
1001 if (hasPoint)
1002 while ((++t).isDigit()) ++numDigits;
1003
1004 if (numDigits == 0)
1005 return false;
1006
1007 auto c = *t;
1008 const bool hasExponent = (c == 'e' || c == 'E');
1009
1010 if (hasExponent)
1011 {
1012 c = *++t;
1013 if (c == '+' || c == '-') ++t;
1014 if (! t.isDigit()) return false;
1015 while ((++t).isDigit()) {}
1016 }
1017
1018 if (! (hasExponent || hasPoint)) return false;
1019
1020 currentValue = CharacterFunctions::getDoubleValue (p); p = t;
1021 return true;
1022 }
1023
1024 bool parseOctalLiteral()
1025 {
1026 auto t = p;
1027 int64 v = *t - '0';
1028 if (v != 0) return false; // first digit of octal must be 0
1029
1030 for (;;)
1031 {
1032 auto digit = (int) (*++t - '0');
1033 if (isPositiveAndBelow (digit, 8)) v = v * 8 + digit;
1034 else if (isPositiveAndBelow (digit, 10)) location.throwError ("Decimal digit in octal constant");
1035 else break;
1036 }
1037
1038 currentValue = v; p = t;
1039 return true;
1040 }
1041
1042 bool parseDecimalLiteral()
1043 {
1044 int64 v = 0;
1045
1046 for (;; ++p)
1047 {
1048 auto digit = (int) (*p - '0');
1049 if (isPositiveAndBelow (digit, 10)) v = v * 10 + digit;
1050 else break;
1051 }
1052
1053 currentValue = v;
1054 return true;
1055 }
1056 };
1057
1058 //==============================================================================
1059 struct ExpressionTreeBuilder final : private TokenIterator
1060 {
1061 ExpressionTreeBuilder (const String code) : TokenIterator (code) {}
1062
1063 BlockStatement* parseStatementList()
1064 {
1065 std::unique_ptr<BlockStatement> b (new BlockStatement (location));
1066
1067 while (currentType != TokenTypes::closeBrace && currentType != TokenTypes::eof)
1068 b->statements.add (parseStatement());
1069
1070 return b.release();
1071 }
1072
1073 void parseFunctionParamsAndBody (FunctionObject& fo)
1074 {
1075 match (TokenTypes::openParen);
1076
1077 while (currentType != TokenTypes::closeParen)
1078 {
1079 auto paramName = currentValue.toString();
1080 match (TokenTypes::identifier);
1081 fo.parameters.add (paramName);
1082
1083 if (currentType != TokenTypes::closeParen)
1084 match (TokenTypes::comma);
1085 }
1086
1087 match (TokenTypes::closeParen);
1088 fo.body.reset (parseBlock());
1089 }
1090
1091 Expression* parseExpression()
1092 {
1093 ExpPtr lhs (parseLogicOperator());
1094
1095 if (matchIf (TokenTypes::question)) return parseTernaryOperator (lhs);
1096 if (matchIf (TokenTypes::assign)) { ExpPtr rhs (parseExpression()); return new Assignment (location, lhs, rhs); }
1097 if (matchIf (TokenTypes::plusEquals)) return parseInPlaceOpExpression<AdditionOp> (lhs);
1098 if (matchIf (TokenTypes::minusEquals)) return parseInPlaceOpExpression<SubtractionOp> (lhs);
1099 if (matchIf (TokenTypes::timesEquals)) return parseInPlaceOpExpression<MultiplyOp> (lhs);
1100 if (matchIf (TokenTypes::divideEquals)) return parseInPlaceOpExpression<DivideOp> (lhs);
1101 if (matchIf (TokenTypes::moduloEquals)) return parseInPlaceOpExpression<ModuloOp> (lhs);
1102 if (matchIf (TokenTypes::leftShiftEquals)) return parseInPlaceOpExpression<LeftShiftOp> (lhs);
1103 if (matchIf (TokenTypes::rightShiftEquals)) return parseInPlaceOpExpression<RightShiftOp> (lhs);
1104
1105 return lhs.release();
1106 }
1107
1108 private:
1109 void throwError (const String& err) const { location.throwError (err); }
1110
1111 template <typename OpType>
1112 Expression* parseInPlaceOpExpression (ExpPtr& lhs)
1113 {
1114 ExpPtr rhs (parseExpression());
1115 Expression* bareLHS = lhs.get(); // careful - bare pointer is deliberately aliased
1116 return new SelfAssignment (location, bareLHS, new OpType (location, lhs, rhs));
1117 }
1118
1119 BlockStatement* parseBlock()
1120 {
1121 match (TokenTypes::openBrace);
1122 std::unique_ptr<BlockStatement> b (parseStatementList());
1123 match (TokenTypes::closeBrace);
1124 return b.release();
1125 }
1126
1127 Statement* parseStatement()
1128 {
1129 if (currentType == TokenTypes::openBrace) return parseBlock();
1130 if (matchIf (TokenTypes::var)) return parseVar();
1131 if (matchIf (TokenTypes::if_)) return parseIf();
1132 if (matchIf (TokenTypes::while_)) return parseDoOrWhileLoop (false);
1133 if (matchIf (TokenTypes::do_)) return parseDoOrWhileLoop (true);
1134 if (matchIf (TokenTypes::for_)) return parseForLoop();
1135 if (matchIf (TokenTypes::return_)) return parseReturn();
1136 if (matchIf (TokenTypes::break_)) return new BreakStatement (location);
1137 if (matchIf (TokenTypes::continue_)) return new ContinueStatement (location);
1138 if (matchIf (TokenTypes::function)) return parseFunction();
1139 if (matchIf (TokenTypes::semicolon)) return new Statement (location);
1140 if (matchIf (TokenTypes::plusplus)) return parsePreIncDec<AdditionOp>();
1141 if (matchIf (TokenTypes::minusminus)) return parsePreIncDec<SubtractionOp>();
1142
1143 if (matchesAny (TokenTypes::openParen, TokenTypes::openBracket))
1144 return matchEndOfStatement (parseFactor());
1145
1146 if (matchesAny (TokenTypes::identifier, TokenTypes::literal, TokenTypes::minus))
1147 return matchEndOfStatement (parseExpression());
1148
1149 throwError ("Found " + getTokenName (currentType) + " when expecting a statement");
1150 return nullptr;
1151 }
1152
1153 Expression* matchEndOfStatement (Expression* ex) { ExpPtr e (ex); if (currentType != TokenTypes::eof) match (TokenTypes::semicolon); return e.release(); }
1154 Expression* matchCloseParen (Expression* ex) { ExpPtr e (ex); match (TokenTypes::closeParen); return e.release(); }
1155
1156 Statement* parseIf()
1157 {
1158 std::unique_ptr<IfStatement> s (new IfStatement (location));
1159 match (TokenTypes::openParen);
1160 s->condition.reset (parseExpression());
1161 match (TokenTypes::closeParen);
1162 s->trueBranch.reset (parseStatement());
1163 s->falseBranch.reset (matchIf (TokenTypes::else_) ? parseStatement() : new Statement (location));
1164 return s.release();
1165 }
1166
1167 Statement* parseReturn()
1168 {
1169 if (matchIf (TokenTypes::semicolon))
1170 return new ReturnStatement (location, new Expression (location));
1171
1172 auto* r = new ReturnStatement (location, parseExpression());
1173 matchIf (TokenTypes::semicolon);
1174 return r;
1175 }
1176
1177 Statement* parseVar()
1178 {
1179 std::unique_ptr<VarStatement> s (new VarStatement (location));
1180 s->name = parseIdentifier();
1181 s->initialiser.reset (matchIf (TokenTypes::assign) ? parseExpression() : new Expression (location));
1182
1183 if (matchIf (TokenTypes::comma))
1184 {
1185 std::unique_ptr<BlockStatement> block (new BlockStatement (location));
1186 block->statements.add (std::move (s));
1187 block->statements.add (parseVar());
1188 return block.release();
1189 }
1190
1191 match (TokenTypes::semicolon);
1192 return s.release();
1193 }
1194
1195 Statement* parseFunction()
1196 {
1197 Identifier name;
1198 auto fn = parseFunctionDefinition (name);
1199
1200 if (name.isNull())
1201 throwError ("Functions defined at statement-level must have a name");
1202
1203 ExpPtr nm (new UnqualifiedName (location, name)), value (new LiteralValue (location, fn));
1204 return new Assignment (location, nm, value);
1205 }
1206
1207 Statement* parseForLoop()
1208 {
1209 std::unique_ptr<LoopStatement> s (new LoopStatement (location, false));
1210 match (TokenTypes::openParen);
1211 s->initialiser.reset (parseStatement());
1212
1213 if (matchIf (TokenTypes::semicolon))
1214 s->condition.reset (new LiteralValue (location, true));
1215 else
1216 {
1217 s->condition.reset (parseExpression());
1218 match (TokenTypes::semicolon);
1219 }
1220
1221 if (matchIf (TokenTypes::closeParen))
1222 s->iterator.reset (new Statement (location));
1223 else
1224 {
1225 s->iterator.reset (parseExpression());
1226 match (TokenTypes::closeParen);
1227 }
1228
1229 s->body.reset (parseStatement());
1230 return s.release();
1231 }
1232
1233 Statement* parseDoOrWhileLoop (bool isDoLoop)
1234 {
1235 std::unique_ptr<LoopStatement> s (new LoopStatement (location, isDoLoop));
1236 s->initialiser.reset (new Statement (location));
1237 s->iterator.reset (new Statement (location));
1238
1239 if (isDoLoop)
1240 {
1241 s->body.reset (parseBlock());
1242 match (TokenTypes::while_);
1243 }
1244
1245 match (TokenTypes::openParen);
1246 s->condition.reset (parseExpression());
1247 match (TokenTypes::closeParen);
1248
1249 if (! isDoLoop)
1250 s->body.reset (parseStatement());
1251
1252 return s.release();
1253 }
1254
1255 Identifier parseIdentifier()
1256 {
1257 Identifier i;
1258 if (currentType == TokenTypes::identifier)
1259 i = currentValue.toString();
1260
1261 match (TokenTypes::identifier);
1262 return i;
1263 }
1264
1265 var parseFunctionDefinition (Identifier& functionName)
1266 {
1267 auto functionStart = location.location;
1268
1269 if (currentType == TokenTypes::identifier)
1270 functionName = parseIdentifier();
1271
1272 std::unique_ptr<FunctionObject> fo (new FunctionObject());
1273 parseFunctionParamsAndBody (*fo);
1274 fo->functionCode = String (functionStart, location.location);
1275 return var (fo.release());
1276 }
1277
1278 Expression* parseFunctionCall (FunctionCall* call, ExpPtr& function)
1279 {
1280 std::unique_ptr<FunctionCall> s (call);
1281 s->object = std::move (function);
1282 match (TokenTypes::openParen);
1283
1284 while (currentType != TokenTypes::closeParen)
1285 {
1286 s->arguments.add (parseExpression());
1287 if (currentType != TokenTypes::closeParen)
1288 match (TokenTypes::comma);
1289 }
1290
1291 return matchCloseParen (s.release());
1292 }
1293
1294 Expression* parseSuffixes (Expression* e)
1295 {
1296 ExpPtr input (e);
1297
1298 if (matchIf (TokenTypes::dot))
1299 return parseSuffixes (new DotOperator (location, input, parseIdentifier()));
1300
1301 if (currentType == TokenTypes::openParen)
1302 return parseSuffixes (parseFunctionCall (new FunctionCall (location), input));
1303
1304 if (matchIf (TokenTypes::openBracket))
1305 {
1306 std::unique_ptr<ArraySubscript> s (new ArraySubscript (location));
1307 s->object = std::move (input);
1308 s->index.reset (parseExpression());
1309 match (TokenTypes::closeBracket);
1310 return parseSuffixes (s.release());
1311 }
1312
1313 if (matchIf (TokenTypes::plusplus)) return parsePostIncDec<AdditionOp> (input);
1314 if (matchIf (TokenTypes::minusminus)) return parsePostIncDec<SubtractionOp> (input);
1315
1316 return input.release();
1317 }
1318
1319 Expression* parseFactor()
1320 {
1321 if (currentType == TokenTypes::identifier) return parseSuffixes (new UnqualifiedName (location, parseIdentifier()));
1322 if (matchIf (TokenTypes::openParen)) return parseSuffixes (matchCloseParen (parseExpression()));
1323 if (matchIf (TokenTypes::true_)) return parseSuffixes (new LiteralValue (location, (int) 1));
1324 if (matchIf (TokenTypes::false_)) return parseSuffixes (new LiteralValue (location, (int) 0));
1325 if (matchIf (TokenTypes::null_)) return parseSuffixes (new LiteralValue (location, var()));
1326 if (matchIf (TokenTypes::undefined)) return parseSuffixes (new Expression (location));
1327
1328 if (currentType == TokenTypes::literal)
1329 {
1330 var v (currentValue); skip();
1331 return parseSuffixes (new LiteralValue (location, v));
1332 }
1333
1334 if (matchIf (TokenTypes::openBrace))
1335 {
1336 std::unique_ptr<ObjectDeclaration> e (new ObjectDeclaration (location));
1337
1338 while (currentType != TokenTypes::closeBrace)
1339 {
1340 auto memberName = currentValue.toString();
1341 match ((currentType == TokenTypes::literal && currentValue.isString())
1342 ? TokenTypes::literal : TokenTypes::identifier);
1343 match (TokenTypes::colon);
1344
1345 e->names.add (memberName);
1346 e->initialisers.add (parseExpression());
1347
1348 if (currentType != TokenTypes::closeBrace)
1349 match (TokenTypes::comma);
1350 }
1351
1352 match (TokenTypes::closeBrace);
1353 return parseSuffixes (e.release());
1354 }
1355
1356 if (matchIf (TokenTypes::openBracket))
1357 {
1358 std::unique_ptr<ArrayDeclaration> e (new ArrayDeclaration (location));
1359
1360 while (currentType != TokenTypes::closeBracket)
1361 {
1362 e->values.add (parseExpression());
1363
1364 if (currentType != TokenTypes::closeBracket)
1365 match (TokenTypes::comma);
1366 }
1367
1368 match (TokenTypes::closeBracket);
1369 return parseSuffixes (e.release());
1370 }
1371
1372 if (matchIf (TokenTypes::function))
1373 {
1374 Identifier name;
1375 var fn = parseFunctionDefinition (name);
1376
1377 if (name.isValid())
1378 throwError ("Inline functions definitions cannot have a name");
1379
1380 return new LiteralValue (location, fn);
1381 }
1382
1383 if (matchIf (TokenTypes::new_))
1384 {
1385 ExpPtr name (new UnqualifiedName (location, parseIdentifier()));
1386
1387 while (matchIf (TokenTypes::dot))
1388 name.reset (new DotOperator (location, name, parseIdentifier()));
1389
1390 return parseFunctionCall (new NewOperator (location), name);
1391 }
1392
1393 throwError ("Found " + getTokenName (currentType) + " when expecting an expression");
1394 return nullptr;
1395 }
1396
1397 template <typename OpType>
1398 Expression* parsePreIncDec()
1399 {
1400 Expression* e = parseFactor(); // careful - bare pointer is deliberately aliased
1401 ExpPtr lhs (e), one (new LiteralValue (location, (int) 1));
1402 return new SelfAssignment (location, e, new OpType (location, lhs, one));
1403 }
1404
1405 template <typename OpType>
1406 Expression* parsePostIncDec (ExpPtr& lhs)
1407 {
1408 Expression* e = lhs.release(); // careful - bare pointer is deliberately aliased
1409 ExpPtr lhs2 (e), one (new LiteralValue (location, (int) 1));
1410 return new PostAssignment (location, e, new OpType (location, lhs2, one));
1411 }
1412
1413 Expression* parseTypeof()
1414 {
1415 std::unique_ptr<FunctionCall> f (new FunctionCall (location));
1416 f->object.reset (new UnqualifiedName (location, "typeof"));
1417 f->arguments.add (parseUnary());
1418 return f.release();
1419 }
1420
1421 Expression* parseUnary()
1422 {
1423 if (matchIf (TokenTypes::minus)) { ExpPtr a (new LiteralValue (location, (int) 0)), b (parseUnary()); return new SubtractionOp (location, a, b); }
1424 if (matchIf (TokenTypes::logicalNot)) { ExpPtr a (new LiteralValue (location, (int) 0)), b (parseUnary()); return new EqualsOp (location, a, b); }
1425 if (matchIf (TokenTypes::plusplus)) return parsePreIncDec<AdditionOp>();
1426 if (matchIf (TokenTypes::minusminus)) return parsePreIncDec<SubtractionOp>();
1427 if (matchIf (TokenTypes::typeof_)) return parseTypeof();
1428
1429 return parseFactor();
1430 }
1431
1432 Expression* parseMultiplyDivide()
1433 {
1434 ExpPtr a (parseUnary());
1435
1436 for (;;)
1437 {
1438 if (matchIf (TokenTypes::times)) { ExpPtr b (parseUnary()); a.reset (new MultiplyOp (location, a, b)); }
1439 else if (matchIf (TokenTypes::divide)) { ExpPtr b (parseUnary()); a.reset (new DivideOp (location, a, b)); }
1440 else if (matchIf (TokenTypes::modulo)) { ExpPtr b (parseUnary()); a.reset (new ModuloOp (location, a, b)); }
1441 else break;
1442 }
1443
1444 return a.release();
1445 }
1446
1447 Expression* parseAdditionSubtraction()
1448 {
1449 ExpPtr a (parseMultiplyDivide());
1450
1451 for (;;)
1452 {
1453 if (matchIf (TokenTypes::plus)) { ExpPtr b (parseMultiplyDivide()); a.reset (new AdditionOp (location, a, b)); }
1454 else if (matchIf (TokenTypes::minus)) { ExpPtr b (parseMultiplyDivide()); a.reset (new SubtractionOp (location, a, b)); }
1455 else break;
1456 }
1457
1458 return a.release();
1459 }
1460
1461 Expression* parseShiftOperator()
1462 {
1463 ExpPtr a (parseAdditionSubtraction());
1464
1465 for (;;)
1466 {
1467 if (matchIf (TokenTypes::leftShift)) { ExpPtr b (parseExpression()); a.reset (new LeftShiftOp (location, a, b)); }
1468 else if (matchIf (TokenTypes::rightShift)) { ExpPtr b (parseExpression()); a.reset (new RightShiftOp (location, a, b)); }
1469 else if (matchIf (TokenTypes::rightShiftUnsigned)) { ExpPtr b (parseExpression()); a.reset (new RightShiftUnsignedOp (location, a, b)); }
1470 else break;
1471 }
1472
1473 return a.release();
1474 }
1475
1476 Expression* parseComparator()
1477 {
1478 ExpPtr a (parseShiftOperator());
1479
1480 for (;;)
1481 {
1482 if (matchIf (TokenTypes::equals)) { ExpPtr b (parseShiftOperator()); a.reset (new EqualsOp (location, a, b)); }
1483 else if (matchIf (TokenTypes::notEquals)) { ExpPtr b (parseShiftOperator()); a.reset (new NotEqualsOp (location, a, b)); }
1484 else if (matchIf (TokenTypes::typeEquals)) { ExpPtr b (parseShiftOperator()); a.reset (new TypeEqualsOp (location, a, b)); }
1485 else if (matchIf (TokenTypes::typeNotEquals)) { ExpPtr b (parseShiftOperator()); a.reset (new TypeNotEqualsOp (location, a, b)); }
1486 else if (matchIf (TokenTypes::lessThan)) { ExpPtr b (parseShiftOperator()); a.reset (new LessThanOp (location, a, b)); }
1487 else if (matchIf (TokenTypes::lessThanOrEqual)) { ExpPtr b (parseShiftOperator()); a.reset (new LessThanOrEqualOp (location, a, b)); }
1488 else if (matchIf (TokenTypes::greaterThan)) { ExpPtr b (parseShiftOperator()); a.reset (new GreaterThanOp (location, a, b)); }
1489 else if (matchIf (TokenTypes::greaterThanOrEqual)) { ExpPtr b (parseShiftOperator()); a.reset (new GreaterThanOrEqualOp (location, a, b)); }
1490 else break;
1491 }
1492
1493 return a.release();
1494 }
1495
1496 Expression* parseLogicOperator()
1497 {
1498 ExpPtr a (parseComparator());
1499
1500 for (;;)
1501 {
1502 if (matchIf (TokenTypes::logicalAnd)) { ExpPtr b (parseComparator()); a.reset (new LogicalAndOp (location, a, b)); }
1503 else if (matchIf (TokenTypes::logicalOr)) { ExpPtr b (parseComparator()); a.reset (new LogicalOrOp (location, a, b)); }
1504 else if (matchIf (TokenTypes::bitwiseAnd)) { ExpPtr b (parseComparator()); a.reset (new BitwiseAndOp (location, a, b)); }
1505 else if (matchIf (TokenTypes::bitwiseOr)) { ExpPtr b (parseComparator()); a.reset (new BitwiseOrOp (location, a, b)); }
1506 else if (matchIf (TokenTypes::bitwiseXor)) { ExpPtr b (parseComparator()); a.reset (new BitwiseXorOp (location, a, b)); }
1507 else break;
1508 }
1509
1510 return a.release();
1511 }
1512
1513 Expression* parseTernaryOperator (ExpPtr& condition)
1514 {
1515 std::unique_ptr<ConditionalOp> e (new ConditionalOp (location));
1516 e->condition = std::move (condition);
1517 e->trueBranch.reset (parseExpression());
1518 match (TokenTypes::colon);
1519 e->falseBranch.reset (parseExpression());
1520 return e.release();
1521 }
1522
1523 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExpressionTreeBuilder)
1524 };
1525
1526 //==============================================================================
1527 static var get (Args a, int index) noexcept { return index < a.numArguments ? a.arguments[index] : var(); }
1528 static bool isInt (Args a, int index) noexcept { return get (a, index).isInt() || get (a, index).isInt64(); }
1529 static int getInt (Args a, int index) noexcept { return get (a, index); }
1530 static double getDouble (Args a, int index) noexcept { return get (a, index); }
1531 static String getString (Args a, int index) noexcept { return get (a, index).toString(); }
1532
1533 //==============================================================================
1534 struct ObjectClass final : public DynamicObject
1535 {
1536 ObjectClass()
1537 {
1538 setMethod ("dump", dump);
1539 setMethod ("clone", cloneFn);
1540 }
1541
1542 static Identifier getClassName() { static const Identifier i ("Object"); return i; }
1543 static var dump ([[maybe_unused]] Args a) { DBG (JSON::toString (a.thisObject)); return var::undefined(); }
1544 static var cloneFn (Args a) { return a.thisObject.clone(); }
1545 };
1546
1547 //==============================================================================
1548 struct ArrayClass final : public DynamicObject
1549 {
1550 ArrayClass()
1551 {
1552 setMethod ("contains", contains);
1553 setMethod ("remove", remove);
1554 setMethod ("join", join);
1555 setMethod ("push", push);
1556 setMethod ("splice", splice);
1557 setMethod ("indexOf", indexOf);
1558 }
1559
1560 static Identifier getClassName() { static const Identifier i ("Array"); return i; }
1561
1562 static var contains (Args a)
1563 {
1564 if (auto* array = a.thisObject.getArray())
1565 return array->contains (get (a, 0));
1566
1567 return false;
1568 }
1569
1570 static var remove (Args a)
1571 {
1572 if (auto* array = a.thisObject.getArray())
1573 array->removeAllInstancesOf (get (a, 0));
1574
1575 return var::undefined();
1576 }
1577
1578 static var join (Args a)
1579 {
1580 StringArray strings;
1581
1582 if (auto* array = a.thisObject.getArray())
1583 for (auto& v : *array)
1584 strings.add (v.toString());
1585
1586 return strings.joinIntoString (getString (a, 0));
1587 }
1588
1589 static var push (Args a)
1590 {
1591 if (auto* array = a.thisObject.getArray())
1592 {
1593 for (int i = 0; i < a.numArguments; ++i)
1594 array->add (a.arguments[i]);
1595
1596 return array->size();
1597 }
1598
1599 return var::undefined();
1600 }
1601
1602 static var splice (Args a)
1603 {
1604 if (auto* array = a.thisObject.getArray())
1605 {
1606 auto arraySize = array->size();
1607 int start = get (a, 0);
1608
1609 if (start < 0)
1610 start = jmax (0, arraySize + start);
1611 else if (start > arraySize)
1612 start = arraySize;
1613
1614 const int num = a.numArguments > 1 ? jlimit (0, arraySize - start, getInt (a, 1))
1615 : arraySize - start;
1616
1617 Array<var> itemsRemoved;
1618 itemsRemoved.ensureStorageAllocated (num);
1619
1620 for (int i = 0; i < num; ++i)
1621 itemsRemoved.add (array->getReference (start + i));
1622
1623 array->removeRange (start, num);
1624
1625 for (int i = 2; i < a.numArguments; ++i)
1626 array->insert (start++, get (a, i));
1627
1628 // std::move() needed here for older compilers
1629 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move")
1630 return std::move (itemsRemoved);
1631 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1632 }
1633
1634 return var::undefined();
1635 }
1636
1637 static var indexOf (Args a)
1638 {
1639 if (auto* array = a.thisObject.getArray())
1640 {
1641 auto target = get (a, 0);
1642
1643 for (int i = (a.numArguments > 1 ? getInt (a, 1) : 0); i < array->size(); ++i)
1644 if (array->getReference (i) == target)
1645 return i;
1646 }
1647
1648 return -1;
1649 }
1650 };
1651
1652 //==============================================================================
1653 struct StringClass final : public DynamicObject
1654 {
1655 StringClass()
1656 {
1657 setMethod ("substring", substring);
1658 setMethod ("indexOf", indexOf);
1659 setMethod ("charAt", charAt);
1660 setMethod ("charCodeAt", charCodeAt);
1661 setMethod ("fromCharCode", fromCharCode);
1662 setMethod ("split", split);
1663 }
1664
1665 static Identifier getClassName() { static const Identifier i ("String"); return i; }
1666
1667 static var fromCharCode (Args a) { return String::charToString (static_cast<juce_wchar> (getInt (a, 0))); }
1668 static var substring (Args a) { return a.thisObject.toString().substring (getInt (a, 0), getInt (a, 1)); }
1669 static var indexOf (Args a) { return a.thisObject.toString().indexOf (getString (a, 0)); }
1670 static var charCodeAt (Args a) { return (int) a.thisObject.toString() [getInt (a, 0)]; }
1671 static var charAt (Args a) { int p = getInt (a, 0); return a.thisObject.toString().substring (p, p + 1); }
1672
1673 static var split (Args a)
1674 {
1675 auto str = a.thisObject.toString();
1676 auto sep = getString (a, 0);
1677 StringArray strings;
1678
1679 if (sep.isNotEmpty())
1680 strings.addTokens (str, sep.substring (0, 1), {});
1681 else // special-case for empty separator: split all chars separately
1682 for (auto pos = str.getCharPointer(); ! pos.isEmpty(); ++pos)
1683 strings.add (String::charToString (*pos));
1684
1685 var array;
1686
1687 for (auto& s : strings)
1688 array.append (s);
1689
1690 return array;
1691 }
1692 };
1693
1694 //==============================================================================
1695 struct MathClass final : public DynamicObject
1696 {
1697 MathClass()
1698 {
1699 setMethod ("abs", Math_abs); setMethod ("round", Math_round);
1700 setMethod ("random", Math_random); setMethod ("randInt", Math_randInt);
1701 setMethod ("min", Math_min); setMethod ("max", Math_max);
1702 setMethod ("range", Math_range); setMethod ("sign", Math_sign);
1703 setMethod ("toDegrees", Math_toDegrees); setMethod ("toRadians", Math_toRadians);
1704 setMethod ("sin", Math_sin); setMethod ("asin", Math_asin);
1705 setMethod ("sinh", Math_sinh); setMethod ("asinh", Math_asinh);
1706 setMethod ("cos", Math_cos); setMethod ("acos", Math_acos);
1707 setMethod ("cosh", Math_cosh); setMethod ("acosh", Math_acosh);
1708 setMethod ("tan", Math_tan); setMethod ("atan", Math_atan);
1709 setMethod ("tanh", Math_tanh); setMethod ("atanh", Math_atanh);
1710 setMethod ("log", Math_log); setMethod ("log10", Math_log10);
1711 setMethod ("exp", Math_exp); setMethod ("pow", Math_pow);
1712 setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt);
1713 setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor);
1714 setMethod ("hypot", Math_hypot);
1715
1716 setProperty ("PI", MathConstants<double>::pi);
1717 setProperty ("E", MathConstants<double>::euler);
1718 setProperty ("SQRT2", MathConstants<double>::sqrt2);
1719 setProperty ("SQRT1_2", std::sqrt (0.5));
1720 setProperty ("LN2", std::log (2.0));
1721 setProperty ("LN10", std::log (10.0));
1722 setProperty ("LOG2E", std::log (MathConstants<double>::euler) / std::log (2.0));
1723 setProperty ("LOG10E", std::log (MathConstants<double>::euler) / std::log (10.0));
1724 }
1725
1726 static var Math_random (Args) { return Random::getSystemRandom().nextDouble(); }
1727 static var Math_randInt (Args a) { return Random::getSystemRandom().nextInt (Range<int> (getInt (a, 0), getInt (a, 1))); }
1728 static var Math_abs (Args a) { return isInt (a, 0) ? var (std::abs (getInt (a, 0))) : var (std::abs (getDouble (a, 0))); }
1729 static var Math_round (Args a) { return isInt (a, 0) ? var (roundToInt (getInt (a, 0))) : var (roundToInt (getDouble (a, 0))); }
1730 static var Math_sign (Args a) { return isInt (a, 0) ? var (sign (getInt (a, 0))) : var (sign (getDouble (a, 0))); }
1731 static var Math_range (Args a) { return isInt (a, 0) ? var (jlimit (getInt (a, 1), getInt (a, 2), getInt (a, 0))) : var (jlimit (getDouble (a, 1), getDouble (a, 2), getDouble (a, 0))); }
1732 static var Math_min (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmin (getInt (a, 0), getInt (a, 1))) : var (jmin (getDouble (a, 0), getDouble (a, 1))); }
1733 static var Math_max (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmax (getInt (a, 0), getInt (a, 1))) : var (jmax (getDouble (a, 0), getDouble (a, 1))); }
1734 static var Math_toDegrees (Args a) { return radiansToDegrees (getDouble (a, 0)); }
1735 static var Math_toRadians (Args a) { return degreesToRadians (getDouble (a, 0)); }
1736 static var Math_sin (Args a) { return std::sin (getDouble (a, 0)); }
1737 static var Math_asin (Args a) { return std::asin (getDouble (a, 0)); }
1738 static var Math_cos (Args a) { return std::cos (getDouble (a, 0)); }
1739 static var Math_acos (Args a) { return std::acos (getDouble (a, 0)); }
1740 static var Math_sinh (Args a) { return std::sinh (getDouble (a, 0)); }
1741 static var Math_cosh (Args a) { return std::cosh (getDouble (a, 0)); }
1742 static var Math_tan (Args a) { return std::tan (getDouble (a, 0)); }
1743 static var Math_tanh (Args a) { return std::tanh (getDouble (a, 0)); }
1744 static var Math_atan (Args a) { return std::atan (getDouble (a, 0)); }
1745 static var Math_log (Args a) { return std::log (getDouble (a, 0)); }
1746 static var Math_log10 (Args a) { return std::log10 (getDouble (a, 0)); }
1747 static var Math_exp (Args a) { return std::exp (getDouble (a, 0)); }
1748 static var Math_pow (Args a) { return std::pow (getDouble (a, 0), getDouble (a, 1)); }
1749 static var Math_sqr (Args a) { return square (getDouble (a, 0)); }
1750 static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); }
1751 static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); }
1752 static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); }
1753 static var Math_hypot (Args a) { return std::hypot (getDouble (a, 0), getDouble (a, 1)); }
1754
1755 // We can't use the std namespace equivalents of these functions without breaking
1756 // compatibility with older versions of OS X.
1757 static var Math_asinh (Args a) { return asinh (getDouble (a, 0)); }
1758 static var Math_acosh (Args a) { return acosh (getDouble (a, 0)); }
1759 static var Math_atanh (Args a) { return atanh (getDouble (a, 0)); }
1760
1761 static Identifier getClassName() { static const Identifier i ("Math"); return i; }
1762 template <typename Type> static Type sign (Type n) noexcept { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
1763 };
1764
1765 //==============================================================================
1766 struct JSONClass final : public DynamicObject
1767 {
1768 JSONClass() { setMethod ("stringify", stringify); }
1769 static Identifier getClassName() { static const Identifier i ("JSON"); return i; }
1770 static var stringify (Args a) { return JSON::toString (get (a, 0)); }
1771 };
1772
1773 //==============================================================================
1774 struct IntegerClass final : public DynamicObject
1775 {
1776 IntegerClass() { setMethod ("parseInt", parseInt); }
1777 static Identifier getClassName() { static const Identifier i ("Integer"); return i; }
1778
1779 static var parseInt (Args a)
1780 {
1781 auto s = getString (a, 0).trim();
1782
1783 return s[0] == '0' ? (s[1] == 'x' ? s.substring (2).getHexValue64() : getOctalValue (s))
1784 : s.getLargeIntValue();
1785 }
1786 };
1787
1788 //==============================================================================
1789 static var trace (Args a) { Logger::outputDebugString (JSON::toString (a.thisObject)); return var::undefined(); }
1790 static var charToInt (Args a) { return (int) (getString (a, 0)[0]); }
1791 static var parseFloat (Args a) { return getDouble (a, 0); }
1792
1793 static var typeof_internal (Args a)
1794 {
1795 var v (get (a, 0));
1796
1797 if (v.isVoid()) return "void";
1798 if (v.isString()) return "string";
1799 if (isNumeric (v)) return "number";
1800 if (isFunction (v) || v.isMethod()) return "function";
1801 if (v.isObject()) return "object";
1802
1803 return "undefined";
1804 }
1805
1806 static var exec (Args a)
1807 {
1808 if (auto* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
1809 root->execute (getString (a, 0));
1810
1811 return var::undefined();
1812 }
1813
1814 static var eval (Args a)
1815 {
1816 if (auto* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
1817 return root->evaluate (getString (a, 0));
1818
1819 return var::undefined();
1820 }
1821};
1822
1823//==============================================================================
1824JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new RootObject())
1825{
1826 registerNativeObject (RootObject::ObjectClass ::getClassName(), new RootObject::ObjectClass());
1827 registerNativeObject (RootObject::ArrayClass ::getClassName(), new RootObject::ArrayClass());
1828 registerNativeObject (RootObject::StringClass ::getClassName(), new RootObject::StringClass());
1829 registerNativeObject (RootObject::MathClass ::getClassName(), new RootObject::MathClass());
1830 registerNativeObject (RootObject::JSONClass ::getClassName(), new RootObject::JSONClass());
1831 registerNativeObject (RootObject::IntegerClass ::getClassName(), new RootObject::IntegerClass());
1832}
1833
1834JavascriptEngine::~JavascriptEngine() {}
1835
1836void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
1837 void JavascriptEngine::stop() noexcept { root->timeout = {}; }
1838
1839 void JavascriptEngine::registerNativeObject (const Identifier& name, DynamicObject* object)
1840{
1841 root->setProperty (name, object);
1842}
1843
1844 Result JavascriptEngine::execute (const String& code)
1845{
1846 try
1847 {
1848 prepareTimeout();
1849 root->execute (code);
1850 }
1851 catch (String& error)
1852 {
1853 return Result::fail (error);
1854 }
1855
1856 return Result::ok();
1857}
1858
1859 var JavascriptEngine::evaluate (const String& code, Result* result)
1860{
1861 try
1862 {
1863 prepareTimeout();
1864 if (result != nullptr) *result = Result::ok();
1865 return root->evaluate (code);
1866 }
1867 catch (String& error)
1868 {
1869 if (result != nullptr) *result = Result::fail (error);
1870 }
1871
1872 return var::undefined();
1873}
1874
1875 var JavascriptEngine::callFunction (const Identifier& function, const var::NativeFunctionArgs& args, Result* result)
1876{
1877 auto returnVal = var::undefined();
1878
1879 try
1880 {
1881 prepareTimeout();
1882 if (result != nullptr) *result = Result::ok();
1883 RootObject::Scope ({}, *root, *root).findAndInvokeMethod (function, args, returnVal);
1884 }
1885 catch (String& error)
1886 {
1887 if (result != nullptr) *result = Result::fail (error);
1888 }
1889
1890 return returnVal;
1891}
1892
1893 var JavascriptEngine::callFunctionObject (DynamicObject* objectScope, const var& functionObject,
1894 const var::NativeFunctionArgs& args, Result* result)
1895{
1896 auto returnVal = var::undefined();
1897
1898 try
1899 {
1900 prepareTimeout();
1901 if (result != nullptr) *result = Result::ok();
1902 RootObject::Scope rootScope ({}, *root, *root);
1903 RootObject::Scope (&rootScope, *root, DynamicObject::Ptr (objectScope))
1904 .invokeMethod (functionObject, args, returnVal);
1905 }
1906 catch (String& error)
1907 {
1908 if (result != nullptr) *result = Result::fail (error);
1909 }
1910
1911 return returnVal;
1912}
1913
1914 const NamedValueSet& JavascriptEngine::getRootObjectProperties() const noexcept
1915{
1916 return root->getProperties();
1917}
1918
1919JUCE_END_IGNORE_WARNINGS_MSVC
1920
1921} // namespace juce
juce::DynamicObject
Definition juce_DynamicObject.h:40
juce::Identifier
Definition juce_Identifier.h:39
juce::JavascriptEngine::stop
void stop() noexcept
Definition juce_Javascript.cpp:1837
juce::JavascriptEngine::getRootObjectProperties
const NamedValueSet & getRootObjectProperties() const noexcept
Definition juce_Javascript.cpp:1914
juce::JavascriptEngine::execute
Result execute(const String &javascriptCode)
Definition juce_Javascript.cpp:1844
juce::JavascriptEngine::callFunction
var callFunction(const Identifier &function, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
Definition juce_Javascript.cpp:1875
juce::JavascriptEngine::evaluate
var evaluate(const String &javascriptCode, Result *errorMessage=nullptr)
Definition juce_Javascript.cpp:1859
juce::JavascriptEngine::registerNativeObject
void registerNativeObject(const Identifier &objectName, DynamicObject *object)
Definition juce_Javascript.cpp:1839
juce::JavascriptEngine::callFunctionObject
var callFunctionObject(DynamicObject *objectScope, const var &functionObject, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
Definition juce_Javascript.cpp:1893
juce::JavascriptEngine::maximumExecutionTime
RelativeTime maximumExecutionTime
Definition juce_Javascript.h:106
juce::JavascriptEngine::~JavascriptEngine
~JavascriptEngine()
Definition juce_Javascript.cpp:1834
juce::NamedValueSet
Definition juce_NamedValueSet.h:35
juce::ReferenceCountedObjectPtr< DynamicObject >
juce::Result
Definition juce_Result.h:57
juce::Result::fail
static Result fail(const String &errorMessage) noexcept
Definition juce_Result.cpp:65
juce::Result::ok
static Result ok() noexcept
Definition juce_Result.h:61
juce::String
Definition juce_String.h:53
juce::Time::getCurrentTime
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Definition juce_Time.cpp:233
juce::var
Definition juce_Variant.h:42
juce::var::undefined
static var undefined() noexcept
Definition juce_Variant.cpp:538
juce::var::NativeFunctionArgs
Definition juce_Variant.h:49