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