OpenShot Audio Library | OpenShotAudio  0.3.1
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 
23 namespace 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 
47 namespace 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 //==============================================================================
63 struct 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 //==============================================================================
1821 JavascriptEngine::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 
1833 void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
1834 void 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 
1890 var JavascriptEngine::callFunctionObject (DynamicObject* objectScope, const var& functionObject,
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
static String toString(const var &objectToFormat, bool allOnOneLine=false, int maximumDecimalPlaces=15)
Definition: juce_JSON.cpp:501
static double getDoubleValue(CharPointerType text) noexcept
static Random & getSystemRandom() noexcept
Definition: juce_Random.cpp:71
static Result ok() noexcept
Definition: juce_Result.h:61
int nextInt() noexcept
Definition: juce_Random.cpp:78
var callFunctionObject(DynamicObject *objectScope, const var &functionObject, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
Definition: juce_Uuid.h:140
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Definition: juce_Time.cpp:218
static const FloatType pi
var callFunction(const Identifier &function, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
static Result fail(const String &errorMessage) noexcept
Definition: juce_Result.cpp:65
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
static Result parseQuotedString(String::CharPointerType &text, var &result)
Definition: juce_JSON.cpp:520
double nextDouble() noexcept
static int getHexDigitValue(juce_wchar digit) noexcept
RelativeTime maximumExecutionTime
Result execute(const String &javascriptCode)
static void JUCE_CALLTYPE outputDebugString(const String &text)
static const FloatType euler
static const FloatType sqrt2
const NamedValueSet & getRootObjectProperties() const noexcept
static bool isLetter(char character) noexcept
static String charToString(juce_wchar character)
static var undefined() noexcept
var evaluate(const String &javascriptCode, Result *errorMessage=nullptr)
static bool isLetterOrDigit(char character) noexcept
void registerNativeObject(const Identifier &objectName, DynamicObject *object)