The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1922 lines
79KB

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