OpenShot Library | libopenshot-audio  0.2.0
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 //==============================================================================
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); }
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  };
131  //==============================================================================
132  struct Scope
133  {
135  : parent (p), root (std::move (rt)),
136  scope (std::move (scp)) {}
137 
138  const Scope* const parent;
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  };
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  return a;
820  }
821 
822  OwnedArray<Expression> values;
823  };
825  //==============================================================================
826  struct FunctionObject : 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  DynamicObject::Ptr clone() override { return *new FunctionObject (*this); }
837 
838  void writeAsJSON (OutputStream& out, int /*indentLevel*/, bool /*allOnOneLine*/, int /*maximumDecimalPlaces*/) 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  };
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:
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 = p.findEndOfWhitespace();
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 : 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 (s.release());
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.reset (function.release());
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.reset (input.release());
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.reset (condition.release());
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 : 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 (Args a) { DBG (JSON::toString (a.thisObject)); ignoreUnused (a); return var::undefined(); }
1544  static var cloneFn (Args a) { return a.thisObject.clone(); }
1545  };
1546 
1547  //==============================================================================
1548  struct ArrayClass : 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  return itemsRemoved;
1629  }
1630 
1631  return var::undefined();
1632  }
1633 
1634  static var indexOf (Args a)
1635  {
1636  if (auto* array = a.thisObject.getArray())
1637  {
1638  auto target = get (a, 0);
1639 
1640  for (int i = (a.numArguments > 1 ? getInt (a, 1) : 0); i < array->size(); ++i)
1641  if (array->getReference(i) == target)
1642  return i;
1643  }
1645  return -1;
1646  }
1647  };
1648 
1649  //==============================================================================
1650  struct StringClass : public DynamicObject
1651  {
1652  StringClass()
1653  {
1654  setMethod ("substring", substring);
1655  setMethod ("indexOf", indexOf);
1656  setMethod ("charAt", charAt);
1657  setMethod ("charCodeAt", charCodeAt);
1658  setMethod ("fromCharCode", fromCharCode);
1659  setMethod ("split", split);
1660  }
1661 
1662  static Identifier getClassName() { static const Identifier i ("String"); return i; }
1663 
1664  static var fromCharCode (Args a) { return String::charToString (static_cast<juce_wchar> (getInt (a, 0))); }
1665  static var substring (Args a) { return a.thisObject.toString().substring (getInt (a, 0), getInt (a, 1)); }
1666  static var indexOf (Args a) { return a.thisObject.toString().indexOf (getString (a, 0)); }
1667  static var charCodeAt (Args a) { return (int) a.thisObject.toString() [getInt (a, 0)]; }
1668  static var charAt (Args a) { int p = getInt (a, 0); return a.thisObject.toString().substring (p, p + 1); }
1669 
1670  static var split (Args a)
1671  {
1672  auto str = a.thisObject.toString();
1673  auto sep = getString (a, 0);
1674  StringArray strings;
1675 
1676  if (sep.isNotEmpty())
1677  strings.addTokens (str, sep.substring (0, 1), {});
1678  else // special-case for empty separator: split all chars separately
1679  for (auto pos = str.getCharPointer(); ! pos.isEmpty(); ++pos)
1680  strings.add (String::charToString (*pos));
1681 
1682  var array;
1683 
1684  for (auto& s : strings)
1685  array.append (s);
1687  return array;
1688  }
1689  };
1690 
1691  //==============================================================================
1692  struct MathClass : public DynamicObject
1693  {
1694  MathClass()
1695  {
1696  setMethod ("abs", Math_abs); setMethod ("round", Math_round);
1697  setMethod ("random", Math_random); setMethod ("randInt", Math_randInt);
1698  setMethod ("min", Math_min); setMethod ("max", Math_max);
1699  setMethod ("range", Math_range); setMethod ("sign", Math_sign);
1700  setMethod ("toDegrees", Math_toDegrees); setMethod ("toRadians", Math_toRadians);
1701  setMethod ("sin", Math_sin); setMethod ("asin", Math_asin);
1702  setMethod ("sinh", Math_sinh); setMethod ("asinh", Math_asinh);
1703  setMethod ("cos", Math_cos); setMethod ("acos", Math_acos);
1704  setMethod ("cosh", Math_cosh); setMethod ("acosh", Math_acosh);
1705  setMethod ("tan", Math_tan); setMethod ("atan", Math_atan);
1706  setMethod ("tanh", Math_tanh); setMethod ("atanh", Math_atanh);
1707  setMethod ("log", Math_log); setMethod ("log10", Math_log10);
1708  setMethod ("exp", Math_exp); setMethod ("pow", Math_pow);
1709  setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt);
1710  setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor);
1711 
1712  setProperty ("PI", MathConstants<double>::pi);
1713  setProperty ("E", MathConstants<double>::euler);
1714  setProperty ("SQRT2", MathConstants<double>::sqrt2);
1715  setProperty ("SQRT1_2", std::sqrt (0.5));
1716  setProperty ("LN2", std::log (2.0));
1717  setProperty ("LN10", std::log (10.0));
1718  setProperty ("LOG2E", std::log (MathConstants<double>::euler) / std::log (2.0));
1719  setProperty ("LOG10E", std::log (MathConstants<double>::euler) / std::log (10.0));
1720  }
1721 
1722  static var Math_random (Args) { return Random::getSystemRandom().nextDouble(); }
1723  static var Math_randInt (Args a) { return Random::getSystemRandom().nextInt (Range<int> (getInt (a, 0), getInt (a, 1))); }
1724  static var Math_abs (Args a) { return isInt (a, 0) ? var (std::abs (getInt (a, 0))) : var (std::abs (getDouble (a, 0))); }
1725  static var Math_round (Args a) { return isInt (a, 0) ? var (roundToInt (getInt (a, 0))) : var (roundToInt (getDouble (a, 0))); }
1726  static var Math_sign (Args a) { return isInt (a, 0) ? var (sign (getInt (a, 0))) : var (sign (getDouble (a, 0))); }
1727  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))); }
1728  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))); }
1729  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))); }
1730  static var Math_toDegrees (Args a) { return radiansToDegrees (getDouble (a, 0)); }
1731  static var Math_toRadians (Args a) { return degreesToRadians (getDouble (a, 0)); }
1732  static var Math_sin (Args a) { return std::sin (getDouble (a, 0)); }
1733  static var Math_asin (Args a) { return std::asin (getDouble (a, 0)); }
1734  static var Math_cos (Args a) { return std::cos (getDouble (a, 0)); }
1735  static var Math_acos (Args a) { return std::acos (getDouble (a, 0)); }
1736  static var Math_sinh (Args a) { return std::sinh (getDouble (a, 0)); }
1737  static var Math_cosh (Args a) { return std::cosh (getDouble (a, 0)); }
1738  static var Math_tan (Args a) { return std::tan (getDouble (a, 0)); }
1739  static var Math_tanh (Args a) { return std::tanh (getDouble (a, 0)); }
1740  static var Math_atan (Args a) { return std::atan (getDouble (a, 0)); }
1741  static var Math_log (Args a) { return std::log (getDouble (a, 0)); }
1742  static var Math_log10 (Args a) { return std::log10 (getDouble (a, 0)); }
1743  static var Math_exp (Args a) { return std::exp (getDouble (a, 0)); }
1744  static var Math_pow (Args a) { return std::pow (getDouble (a, 0), getDouble (a, 1)); }
1745  static var Math_sqr (Args a) { return square (getDouble (a, 0)); }
1746  static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); }
1747  static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); }
1748  static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); }
1749 
1750  // We can't use the std namespace equivalents of these functions without breaking
1751  // compatibility with older versions of OS X.
1752  static var Math_asinh (Args a) { return asinh (getDouble (a, 0)); }
1753  static var Math_acosh (Args a) { return acosh (getDouble (a, 0)); }
1754  static var Math_atanh (Args a) { return atanh (getDouble (a, 0)); }
1756  static Identifier getClassName() { static const Identifier i ("Math"); return i; }
1757  template <typename Type> static Type sign (Type n) noexcept { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
1758  };
1759 
1760  //==============================================================================
1761  struct JSONClass : public DynamicObject
1762  {
1763  JSONClass() { setMethod ("stringify", stringify); }
1764  static Identifier getClassName() { static const Identifier i ("JSON"); return i; }
1765  static var stringify (Args a) { return JSON::toString (get (a, 0)); }
1766  };
1767 
1768  //==============================================================================
1769  struct IntegerClass : public DynamicObject
1770  {
1771  IntegerClass() { setMethod ("parseInt", parseInt); }
1772  static Identifier getClassName() { static const Identifier i ("Integer"); return i; }
1773 
1774  static var parseInt (Args a)
1775  {
1776  auto s = getString (a, 0).trim();
1777 
1778  return s[0] == '0' ? (s[1] == 'x' ? s.substring(2).getHexValue64() : getOctalValue (s))
1779  : s.getLargeIntValue();
1780  }
1781  };
1782 
1783  //==============================================================================
1784  static var trace (Args a) { Logger::outputDebugString (JSON::toString (a.thisObject)); return var::undefined(); }
1785  static var charToInt (Args a) { return (int) (getString (a, 0)[0]); }
1786  static var parseFloat (Args a) { return getDouble (a, 0); }
1787 
1788  static var typeof_internal (Args a)
1789  {
1790  var v (get (a, 0));
1791 
1792  if (v.isVoid()) return "void";
1793  if (v.isString()) return "string";
1794  if (isNumeric (v)) return "number";
1795  if (isFunction (v) || v.isMethod()) return "function";
1796  if (v.isObject()) return "object";
1797 
1798  return "undefined";
1799  }
1800 
1801  static var exec (Args a)
1802  {
1803  if (auto* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
1804  root->execute (getString (a, 0));
1805 
1806  return var::undefined();
1807  }
1808 
1809  static var eval (Args a)
1810  {
1811  if (auto* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
1812  return root->evaluate (getString (a, 0));
1814  return var::undefined();
1815  }
1816 };
1817 
1818 //==============================================================================
1819 JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new RootObject())
1820 {
1821  registerNativeObject (RootObject::ObjectClass ::getClassName(), new RootObject::ObjectClass());
1822  registerNativeObject (RootObject::ArrayClass ::getClassName(), new RootObject::ArrayClass());
1823  registerNativeObject (RootObject::StringClass ::getClassName(), new RootObject::StringClass());
1824  registerNativeObject (RootObject::MathClass ::getClassName(), new RootObject::MathClass());
1825  registerNativeObject (RootObject::JSONClass ::getClassName(), new RootObject::JSONClass());
1826  registerNativeObject (RootObject::IntegerClass ::getClassName(), new RootObject::IntegerClass());
1827 }
1830 
1831 void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
1832 void JavascriptEngine::stop() noexcept { root->timeout = {}; }
1835 {
1836  root->setProperty (name, object);
1837 }
1838 
1840 {
1841  try
1842  {
1843  prepareTimeout();
1844  root->execute (code);
1845  }
1846  catch (String& error)
1847  {
1848  return Result::fail (error);
1849  }
1850 
1851  return Result::ok();
1852 }
1853 
1854 var JavascriptEngine::evaluate (const String& code, Result* result)
1855 {
1856  try
1857  {
1858  prepareTimeout();
1859  if (result != nullptr) *result = Result::ok();
1860  return root->evaluate (code);
1861  }
1862  catch (String& error)
1863  {
1864  if (result != nullptr) *result = Result::fail (error);
1865  }
1866 
1867  return var::undefined();
1868 }
1869 
1870 var JavascriptEngine::callFunction (const Identifier& function, const var::NativeFunctionArgs& args, Result* result)
1871 {
1872  auto returnVal = var::undefined();
1873 
1874  try
1875  {
1876  prepareTimeout();
1877  if (result != nullptr) *result = Result::ok();
1878  RootObject::Scope ({}, *root, *root).findAndInvokeMethod (function, args, returnVal);
1879  }
1880  catch (String& error)
1881  {
1882  if (result != nullptr) *result = Result::fail (error);
1883  }
1884 
1885  return returnVal;
1886 }
1887 
1888 var JavascriptEngine::callFunctionObject (DynamicObject* objectScope, const var& functionObject,
1889  const var::NativeFunctionArgs& args, Result* result)
1890 {
1891  auto returnVal = var::undefined();
1892 
1893  try
1894  {
1895  prepareTimeout();
1896  if (result != nullptr) *result = Result::ok();
1897  RootObject::Scope rootScope ({}, *root, *root);
1898  RootObject::Scope (&rootScope, *root, DynamicObject::Ptr (objectScope))
1899  .invokeMethod (functionObject, args, returnVal);
1900  }
1901  catch (String& error)
1902  {
1903  if (result != nullptr) *result = Result::fail (error);
1904  }
1905 
1906  return returnVal;
1907 }
1908 
1910 {
1911  return root->getProperties();
1912 }
1913 
1914 #if JUCE_MSVC
1915  #pragma warning (pop)
1916 #endif
1917 
1918 } // namespace juce
Wraps a pointer to a null-terminated ASCII character string, and provides various methods to operate ...
ElementType * begin() const noexcept
Returns a pointer to the first element in the array.
Definition: juce_Array.h:309
static String toString(const var &objectToFormat, bool allOnOneLine=false, int maximumDecimalPlaces=15)
Returns a string which contains a JSON-formatted representation of the var object.
Definition: juce_JSON.cpp:512
static double getDoubleValue(CharPointerType text) noexcept
Parses a character string, to read a floating-point value.
static Random & getSystemRandom() noexcept
The overhead of creating a new Random object is fairly small, but if you want to avoid it...
Definition: juce_Random.cpp:71
static Result ok() noexcept
Creates and returns a &#39;successful&#39; result.
Definition: juce_Result.h:65
bool isDigit() const noexcept
Returns true if the first character of this string is a digit.
var * getVarPointer(const Identifier &name) const noexcept
Returns a pointer to the var that holds a named value, or null if there is no value with this name...
Represents a string identifier, designed for accessing properties by name.
int nextInt() noexcept
Returns the next random 32 bit integer.
Definition: juce_Random.cpp:78
A variant class, that can be used to hold a range of primitive values.
Definition: juce_Variant.h:45
void ensureStorageAllocated(int minNumElements)
Increases the array&#39;s internal storage to hold a minimum number of elements.
Definition: juce_Array.h:1019
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition: juce_Array.h:375
virtual const var & getProperty(const Identifier &propertyName) const
Returns a named property.
var callFunctionObject(DynamicObject *objectScope, const var &functionObject, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
Calls a function object in the namespace of a dynamic object, and returns the result.
void parseString(StringRef text, int base)
Reads the numeric value from a string.
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
Definition: juce_String.h:1200
bool isEmpty() const noexcept
Returns true if this pointer is pointing to a null character.
A special array for holding a list of strings.
The JUCE String class!
Definition: juce_String.h:42
bool isNull() const noexcept
Returns true if this Identifier is null.
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
Definition: juce_Time.cpp:218
bool isValid() const noexcept
Returns true if this Identifier is not null.
int size() const
If the var is an array, this returns the number of elements.
CharPointer_UTF8 findEndOfWhitespace() const noexcept
Returns the first non-whitespace character in the string.
An arbitrarily large integer class.
var callFunction(const Identifier &function, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
Calls a function in the root namespace, and returns the result.
static Result fail(const String &errorMessage) noexcept
Creates a &#39;failure&#39; result.
Definition: juce_Result.cpp:65
Represents a dynamically implemented object.
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Breaks up a string into tokens and adds them to this array.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
Returns a pointer to the first occurrence of a substring in a string.
static Result parseQuotedString(String::CharPointerType &text, var &result)
Parses a quoted string-literal in JSON format, returning the un-escaped result in the result paramete...
Definition: juce_JSON.cpp:531
Holds a set of named var objects.
double nextDouble() noexcept
Returns the next random floating-point number.
void stop() noexcept
When called from another thread, causes the interpreter to time-out as soon as possible.
static int getHexDigitValue(juce_wchar digit) noexcept
Returns 0 to 16 for &#39;0&#39; to &#39;F", or -1 for characters that aren&#39;t a legal hex digit.
Represents the &#39;success&#39; or &#39;failure&#39; of an operation, and holds an associated error message to descr...
Definition: juce_Result.h:60
RelativeTime maximumExecutionTime
This value indicates how long a call to one of the evaluate methods is permitted to run before timing...
var invoke(const Identifier &method, const var *arguments, int numArguments) const
Invokes a named method call with a list of arguments.
Array< var > * getArray() const noexcept
If this variant holds an array, this provides access to it.
Result execute(const String &javascriptCode)
Attempts to parse and run a block of javascript code.
static void JUCE_CALLTYPE outputDebugString(const String &text)
Writes a message to the standard error stream.
NamedValueSet & getProperties() noexcept
Returns the NamedValueSet that holds the object&#39;s properties.
int indexOf(StringRef textToLookFor) const noexcept
Searches for a substring within this string.
The base class for streams that write data to some kind of destination.
Holds a resizable array of primitive or copy-by-value objects.
Definition: juce_Array.h:59
const String & toString() const noexcept
Returns this identifier as a string.
int compareUpTo(const CharPointer other, const int maxChars) const noexcept
Compares this string with another one, up to a specified number of characters.
int size() const noexcept
Returns the current number of elements in the array.
Definition: juce_Array.h:219
This structure is passed to a NativeFunction callback, and contains invocation details about the func...
Definition: juce_Variant.h:52
String::CharPointerType getCharPointer() const noexcept
Returns this identifier&#39;s raw string pointer.
ReferencedType * get() const noexcept
Returns the object that this pointer references.
const NamedValueSet & getRootObjectProperties() const noexcept
Provides access to the set of properties of the root namespace object.
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
Joins the strings in the array together into one string.
static bool isLetter(char character) noexcept
Checks whether a character is alphabetic.
void append(const var &valueToAppend)
Appends an element to the var, converting it to an array if it isn&#39;t already one. ...
A smart-pointer class which points to a reference-counted object.
static String charToString(juce_wchar character)
Creates a string from a single character.
static var undefined() noexcept
Returns a var object that can be used where you need the javascript "undefined" value.
An array designed for holding objects.
var evaluate(const String &javascriptCode, Result *errorMessage=nullptr)
Attempts to parse and run a javascript expression, and returns the result.
Commonly used mathematical constants.
String initialSectionContainingOnly(StringRef permittedCharacters) const
Returns a section from the start of the string that only contains a certain set of characters...
bool hasSameTypeAs(const var &other) const noexcept
Returns true if this var has the same type as the one supplied.
Holds an absolute date and time.
Definition: juce_Time.h:40
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
void registerNativeObject(const Identifier &objectName, DynamicObject *object)
Adds a native object to the root namespace.
void add(String stringToAdd)
Appends a string at the end of the array.
var clone() const noexcept
Returns a deep copy of this object.
int64 toInt64() const noexcept
Attempts to get the lowest 64 bits of the value as an integer.
JavascriptEngine()
Creates an instance of the engine.
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
virtual bool hasMethod(const Identifier &methodName) const
Checks whether this object has the specified method.