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