JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_Javascript.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26#define JUCE_JS_OPERATORS(X) \
27 X(semicolon, ";") X(dot, ".") X(comma, ",") \
28 X(openParen, "(") X(closeParen, ")") X(openBrace, "{") X(closeBrace, "}") \
29 X(openBracket, "[") X(closeBracket, "]") X(colon, ":") X(question, "?") \
30 X(typeEquals, "===") X(equals, "==") X(assign, "=") \
31 X(typeNotEquals, "!==") X(notEquals, "!=") X(logicalNot, "!") \
32 X(plusEquals, "+=") X(plusplus, "++") X(plus, "+") \
33 X(minusEquals, "-=") X(minusminus, "--") X(minus, "-") \
34 X(timesEquals, "*=") X(times, "*") X(divideEquals, "/=") X(divide, "/") \
35 X(moduloEquals, "%=") X(modulo, "%") X(xorEquals, "^=") X(bitwiseXor, "^") \
36 X(andEquals, "&=") X(logicalAnd, "&&") X(bitwiseAnd, "&") \
37 X(orEquals, "|=") X(logicalOr, "||") X(bitwiseOr, "|") \
38 X(leftShiftEquals, "<<=") X(lessThanOrEqual, "<=") X(leftShift, "<<") X(lessThan, "<") \
39 X(rightShiftUnsigned, ">>>") X(rightShiftEquals, ">>=") X(rightShift, ">>") X(greaterThanOrEqual, ">=") X(greaterThan, ">")
40
41#define JUCE_JS_KEYWORDS(X) \
42 X(var, "var") X(if_, "if") X(else_, "else") X(do_, "do") X(null_, "null") \
43 X(while_, "while") X(for_, "for") X(break_, "break") X(continue_, "continue") X(undefined, "undefined") \
44 X(function, "function") X(return_, "return") X(true_, "true") X(false_, "false") X(new_, "new") \
45 X(typeof_, "typeof")
46
47namespace TokenTypes
48{
49 #define JUCE_DECLARE_JS_TOKEN(name, str) static const char* const name = str;
50 JUCE_JS_KEYWORDS (JUCE_DECLARE_JS_TOKEN)
51 JUCE_JS_OPERATORS (JUCE_DECLARE_JS_TOKEN)
52 JUCE_DECLARE_JS_TOKEN (eof, "$eof")
53 JUCE_DECLARE_JS_TOKEN (literal, "$literal")
54 JUCE_DECLARE_JS_TOKEN (identifier, "$identifier")
55}
56
57JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4702)
58
59//==============================================================================
61{
63 {
64 setMethod ("exec", exec);
65 setMethod ("eval", eval);
66 setMethod ("trace", trace);
67 setMethod ("charToInt", charToInt);
68 setMethod ("parseInt", IntegerClass::parseInt);
69 setMethod ("typeof", typeof_internal);
70 setMethod ("parseFloat", parseFloat);
71 }
72
73 Time timeout;
74
75 using Args = const var::NativeFunctionArgs&;
76 using TokenType = const char*;
77
78 void execute (const String& code)
79 {
81 std::unique_ptr<BlockStatement> (tb.parseStatementList())->perform (Scope ({}, *this, *this), nullptr);
82 }
83
84 var evaluate (const String& code)
85 {
87 return ExpPtr (tb.parseExpression())->getResult (Scope ({}, *this, *this));
88 }
89
90 //==============================================================================
91 static bool areTypeEqual (const var& a, const var& b)
92 {
93 return a.hasSameTypeAs (b) && isFunction (a) == isFunction (b)
94 && (((a.isUndefined() || a.isVoid()) && (b.isUndefined() || b.isVoid())) || a == b);
95 }
96
97 static String getTokenName (TokenType t) { return t[0] == '$' ? String (t + 1) : ("'" + String (t) + "'"); }
98 static bool isFunction (const var& v) noexcept { return dynamic_cast<FunctionObject*> (v.getObject()) != nullptr; }
99 static bool isNumeric (const var& v) noexcept { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool(); }
100 static bool isNumericOrUndefined (const var& v) noexcept { return isNumeric (v) || v.isUndefined(); }
101 static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s.initialSectionContainingOnly ("01234567"), 8); return b.toInt64(); }
102 static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; }
103 static var* getPropertyPointer (DynamicObject& o, const Identifier& i) noexcept { return o.getProperties().getVarPointer (i); }
104
105 //==============================================================================
107 {
108 CodeLocation (const String& code) noexcept : program (code), location (program.getCharPointer()) {}
109 CodeLocation (const CodeLocation& other) noexcept : program (other.program), location (other.location) {}
110
111 void throwError (const String& message) const
112 {
113 int col = 1, line = 1;
114
115 for (auto i = program.getCharPointer(); i < location && ! i.isEmpty(); ++i)
116 {
117 ++col;
118 if (*i == '\n') { col = 1; ++line; }
119 }
120
121 throw "Line " + String (line) + ", column " + String (col) + " : " + message;
122 }
123
124 String program;
126 };
127
128 //==============================================================================
129 struct Scope
130 {
132 : parent (p), root (std::move (rt)),
133 scope (std::move (scp)) {}
134
135 const Scope* const parent;
137 DynamicObject::Ptr scope;
138
139 var findFunctionCall (const CodeLocation& location, const var& targetObject, const Identifier& functionName) const
140 {
141 if (auto* o = targetObject.getDynamicObject())
142 {
143 if (auto* prop = getPropertyPointer (*o, functionName))
144 return *prop;
145
146 for (auto* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
147 p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
148 {
149 if (auto* prop = getPropertyPointer (*p, functionName))
150 return *prop;
151 }
152
153 // if there's a class with an overridden DynamicObject::hasMethod, this avoids an error
154 if (o->hasMethod (functionName))
155 return {};
156 }
157
158 if (targetObject.isString())
159 if (auto* m = findRootClassProperty (StringClass::getClassName(), functionName))
160 return *m;
161
162 if (targetObject.isArray())
163 if (auto* m = findRootClassProperty (ArrayClass::getClassName(), functionName))
164 return *m;
165
166 if (auto* m = findRootClassProperty (ObjectClass::getClassName(), functionName))
167 return *m;
168
169 location.throwError ("Unknown function '" + functionName.toString() + "'");
170 return {};
171 }
172
173 var* findRootClassProperty (const Identifier& className, const Identifier& propName) const
174 {
175 if (auto* cls = root->getProperty (className).getDynamicObject())
176 return getPropertyPointer (*cls, propName);
177
178 return nullptr;
179 }
180
181 var findSymbolInParentScopes (const Identifier& name) const
182 {
183 if (auto v = getPropertyPointer (*scope, name))
184 return *v;
185
186 return parent != nullptr ? parent->findSymbolInParentScopes (name)
187 : var::undefined();
188 }
189
190 bool findAndInvokeMethod (const Identifier& function, const var::NativeFunctionArgs& args, var& result) const
191 {
192 auto* target = args.thisObject.getDynamicObject();
193
194 if (target == nullptr || target == scope.get())
195 {
196 if (auto* m = getPropertyPointer (*scope, function))
197 {
198 if (auto fo = dynamic_cast<FunctionObject*> (m->getObject()))
199 {
200 result = fo->invoke (*this, args);
201 return true;
202 }
203 }
204 }
205
206 const auto& props = scope->getProperties();
207
208 for (int i = 0; i < props.size(); ++i)
209 if (auto* o = props.getValueAt (i).getDynamicObject())
210 if (Scope (this, *root, *o).findAndInvokeMethod (function, args, result))
211 return true;
212
213 return false;
214 }
215
216 bool invokeMethod (const var& m, const var::NativeFunctionArgs& args, var& result) const
217 {
218 if (isFunction (m))
219 {
220 auto* target = args.thisObject.getDynamicObject();
221
222 if (target == nullptr || target == scope.get())
223 {
224 if (auto fo = dynamic_cast<FunctionObject*> (m.getObject()))
225 {
226 result = fo->invoke (*this, args);
227 return true;
228 }
229 }
230 }
231
232 return false;
233 }
234
235 void checkTimeOut (const CodeLocation& location) const
236 {
237 if (Time::getCurrentTime() > root->timeout)
238 location.throwError (root->timeout == Time() ? "Interrupted" : "Execution timed-out");
239 }
240
242 };
243
244 //==============================================================================
246 {
247 Statement (const CodeLocation& l) noexcept : location (l) {}
248 virtual ~Statement() = default;
249
250 enum ResultCode { ok = 0, returnWasHit, breakWasHit, continueWasHit };
251 virtual ResultCode perform (const Scope&, var*) const { return ok; }
252
253 CodeLocation location;
255 };
256
257 struct Expression : public Statement
258 {
259 Expression (const CodeLocation& l) noexcept : Statement (l) {}
260
261 virtual var getResult (const Scope&) const { return var::undefined(); }
262 virtual void assign (const Scope&, const var&) const { location.throwError ("Cannot assign to this expression!"); }
263
264 ResultCode perform (const Scope& s, var*) const override { getResult (s); return ok; }
265 };
266
268
270 {
271 BlockStatement (const CodeLocation& l) noexcept : Statement (l) {}
272
273 ResultCode perform (const Scope& s, var* returnedValue) const override
274 {
275 for (auto* statement : statements)
276 if (auto r = statement->perform (s, returnedValue))
277 return r;
278
279 return ok;
280 }
281
282 OwnedArray<Statement> statements;
283 };
284
286 {
287 IfStatement (const CodeLocation& l) noexcept : Statement (l) {}
288
289 ResultCode perform (const Scope& s, var* returnedValue) const override
290 {
291 return (condition->getResult (s) ? trueBranch : falseBranch)->perform (s, returnedValue);
292 }
293
294 ExpPtr condition;
295 std::unique_ptr<Statement> trueBranch, falseBranch;
296 };
297
299 {
300 VarStatement (const CodeLocation& l) noexcept : Statement (l) {}
301
302 ResultCode perform (const Scope& s, var*) const override
303 {
304 s.scope->setProperty (name, initialiser->getResult (s));
305 return ok;
306 }
307
308 Identifier name;
309 ExpPtr initialiser;
310 };
311
313 {
314 LoopStatement (const CodeLocation& l, bool isDo) noexcept : Statement (l), isDoLoop (isDo) {}
315
316 ResultCode perform (const Scope& s, var* returnedValue) const override
317 {
318 initialiser->perform (s, nullptr);
319
320 while (isDoLoop || condition->getResult (s))
321 {
322 s.checkTimeOut (location);
323 auto r = body->perform (s, returnedValue);
324
325 if (r == returnWasHit) return r;
326 if (r == breakWasHit) break;
327
328 iterator->perform (s, nullptr);
329
330 if (isDoLoop && r != continueWasHit && ! condition->getResult (s))
331 break;
332 }
333
334 return ok;
335 }
336
337 std::unique_ptr<Statement> initialiser, iterator, body;
338 ExpPtr condition;
339 bool isDoLoop;
340 };
341
343 {
344 ReturnStatement (const CodeLocation& l, Expression* v) noexcept : Statement (l), returnValue (v) {}
345
346 ResultCode perform (const Scope& s, var* ret) const override
347 {
348 if (ret != nullptr) *ret = returnValue->getResult (s);
349 return returnWasHit;
350 }
351
352 ExpPtr returnValue;
353 };
354
356 {
357 BreakStatement (const CodeLocation& l) noexcept : Statement (l) {}
358 ResultCode perform (const Scope&, var*) const override { return breakWasHit; }
359 };
360
362 {
363 ContinueStatement (const CodeLocation& l) noexcept : Statement (l) {}
364 ResultCode perform (const Scope&, var*) const override { return continueWasHit; }
365 };
366
368 {
369 LiteralValue (const CodeLocation& l, const var& v) noexcept : Expression (l), value (v) {}
370 var getResult (const Scope&) const override { return value; }
371 var value;
372 };
373
375 {
376 UnqualifiedName (const CodeLocation& l, const Identifier& n) noexcept : Expression (l), name (n) {}
377
378 var getResult (const Scope& s) const override { return s.findSymbolInParentScopes (name); }
379
380 void assign (const Scope& s, const var& newValue) const override
381 {
382 if (auto* v = getPropertyPointer (*s.scope, name))
383 *v = newValue;
384 else
385 s.root->setProperty (name, newValue);
386 }
387
388 Identifier name;
389 };
390
392 {
393 DotOperator (const CodeLocation& l, ExpPtr& p, const Identifier& c) noexcept : Expression (l), parent (p.release()), child (c) {}
394
395 var getResult (const Scope& s) const override
396 {
397 auto p = parent->getResult (s);
398 static const Identifier lengthID ("length");
399
400 if (child == lengthID)
401 {
402 if (auto* array = p.getArray()) return array->size();
403 if (p.isString()) return p.toString().length();
404 }
405
406 if (auto* o = p.getDynamicObject())
407 if (auto* v = getPropertyPointer (*o, child))
408 return *v;
409
410 return var::undefined();
411 }
412
413 void assign (const Scope& s, const var& newValue) const override
414 {
415 if (auto* o = parent->getResult (s).getDynamicObject())
416 o->setProperty (child, newValue);
417 else
418 Expression::assign (s, newValue);
419 }
420
421 ExpPtr parent;
422 Identifier child;
423 };
424
426 {
427 ArraySubscript (const CodeLocation& l) noexcept : Expression (l) {}
428
429 var getResult (const Scope& s) const override
430 {
431 auto arrayVar = object->getResult (s); // must stay alive for the scope of this method
432 auto key = index->getResult (s);
433
434 if (const auto* array = arrayVar.getArray())
435 if (key.isInt() || key.isInt64() || key.isDouble())
436 return (*array) [static_cast<int> (key)];
437
438 if (auto* o = arrayVar.getDynamicObject())
439 if (key.isString())
440 if (auto* v = getPropertyPointer (*o, Identifier (key)))
441 return *v;
442
443 return var::undefined();
444 }
445
446 void assign (const Scope& s, const var& newValue) const override
447 {
448 auto arrayVar = object->getResult (s); // must stay alive for the scope of this method
449 auto key = index->getResult (s);
450
451 if (auto* array = arrayVar.getArray())
452 {
453 if (key.isInt() || key.isInt64() || key.isDouble())
454 {
455 const int i = key;
456 while (array->size() < i)
457 array->add (var::undefined());
458
459 array->set (i, newValue);
460 return;
461 }
462 }
463
464 if (auto* o = arrayVar.getDynamicObject())
465 {
466 if (key.isString())
467 {
468 o->setProperty (Identifier (key), newValue);
469 return;
470 }
471 }
472
473 Expression::assign (s, newValue);
474 }
475
476 ExpPtr object, index;
477 };
478
480 {
481 BinaryOperatorBase (const CodeLocation& l, ExpPtr& a, ExpPtr& b, TokenType op) noexcept
482 : Expression (l), lhs (a.release()), rhs (b.release()), operation (op) {}
483
484 ExpPtr lhs, rhs;
485 TokenType operation;
486 };
487
489 {
490 BinaryOperator (const CodeLocation& l, ExpPtr& a, ExpPtr& b, TokenType op) noexcept
491 : BinaryOperatorBase (l, a, b, op) {}
492
493 virtual var getWithUndefinedArg() const { return var::undefined(); }
494 virtual var getWithDoubles (double, double) const { return throwError ("Double"); }
495 virtual var getWithInts (int64, int64) const { return throwError ("Integer"); }
496 virtual var getWithArrayOrObject (const var& a, const var&) const { return throwError (a.isArray() ? "Array" : "Object"); }
497 virtual var getWithStrings (const String&, const String&) const { return throwError ("String"); }
498
499 var getResult (const Scope& s) const override
500 {
501 var a (lhs->getResult (s)), b (rhs->getResult (s));
502
503 if ((a.isUndefined() || a.isVoid()) && (b.isUndefined() || b.isVoid()))
504 return getWithUndefinedArg();
505
506 if (isNumericOrUndefined (a) && isNumericOrUndefined (b))
507 return (a.isDouble() || b.isDouble()) ? getWithDoubles (a, b) : getWithInts (a, b);
508
509 if (a.isArray() || a.isObject())
510 return getWithArrayOrObject (a, b);
511
512 return getWithStrings (a.toString(), b.toString());
513 }
514
515 var throwError (const char* typeName) const
516 { location.throwError (getTokenName (operation) + " is not allowed on the " + typeName + " type"); return {}; }
517 };
518
520 {
521 EqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::equals) {}
522 var getWithUndefinedArg() const override { return true; }
523 var getWithDoubles (double a, double b) const override { return exactlyEqual (a, b); }
524 var getWithInts (int64 a, int64 b) const override { return a == b; }
525 var getWithStrings (const String& a, const String& b) const override { return a == b; }
526 var getWithArrayOrObject (const var& a, const var& b) const override { return a == b; }
527 };
528
530 {
531 NotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::notEquals) {}
532 var getWithUndefinedArg() const override { return false; }
533 var getWithDoubles (double a, double b) const override { return ! exactlyEqual (a, b); }
534 var getWithInts (int64 a, int64 b) const override { return a != b; }
535 var getWithStrings (const String& a, const String& b) const override { return a != b; }
536 var getWithArrayOrObject (const var& a, const var& b) const override { return a != b; }
537 };
538
540 {
541 LessThanOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::lessThan) {}
542 var getWithDoubles (double a, double b) const override { return a < b; }
543 var getWithInts (int64 a, int64 b) const override { return a < b; }
544 var getWithStrings (const String& a, const String& b) const override { return a < b; }
545 };
546
548 {
549 LessThanOrEqualOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::lessThanOrEqual) {}
550 var getWithDoubles (double a, double b) const override { return a <= b; }
551 var getWithInts (int64 a, int64 b) const override { return a <= b; }
552 var getWithStrings (const String& a, const String& b) const override { return a <= b; }
553 };
554
556 {
557 GreaterThanOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::greaterThan) {}
558 var getWithDoubles (double a, double b) const override { return a > b; }
559 var getWithInts (int64 a, int64 b) const override { return a > b; }
560 var getWithStrings (const String& a, const String& b) const override { return a > b; }
561 };
562
564 {
565 GreaterThanOrEqualOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::greaterThanOrEqual) {}
566 var getWithDoubles (double a, double b) const override { return a >= b; }
567 var getWithInts (int64 a, int64 b) const override { return a >= b; }
568 var getWithStrings (const String& a, const String& b) const override { return a >= b; }
569 };
570
572 {
573 AdditionOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::plus) {}
574 var getWithDoubles (double a, double b) const override { return a + b; }
575 var getWithInts (int64 a, int64 b) const override { return a + b; }
576 var getWithStrings (const String& a, const String& b) const override { return a + b; }
577 };
578
580 {
581 SubtractionOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::minus) {}
582 var getWithDoubles (double a, double b) const override { return a - b; }
583 var getWithInts (int64 a, int64 b) const override { return a - b; }
584 };
585
587 {
588 MultiplyOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::times) {}
589 var getWithDoubles (double a, double b) const override { return a * b; }
590 var getWithInts (int64 a, int64 b) const override { return a * b; }
591 };
592
594 {
595 DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
596 var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits<double>::infinity() : a / b; }
597 var getWithInts (int64 a, int64 b) const override { return b != 0 ? var ((double) a / (double) b) : var (std::numeric_limits<double>::infinity()); }
598 };
599
601 {
602 ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {}
603 var getWithDoubles (double a, double b) const override { return exactlyEqual (b, 0.0) ? std::numeric_limits<double>::infinity() : fmod (a, b); }
604 var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); }
605 };
606
608 {
609 BitwiseOrOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseOr) {}
610 var getWithInts (int64 a, int64 b) const override { return a | b; }
611 };
612
614 {
615 BitwiseAndOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseAnd) {}
616 var getWithInts (int64 a, int64 b) const override { return a & b; }
617 };
618
620 {
621 BitwiseXorOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::bitwiseXor) {}
622 var getWithInts (int64 a, int64 b) const override { return a ^ b; }
623 };
624
626 {
627 LeftShiftOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::leftShift) {}
628 var getWithInts (int64 a, int64 b) const override { return ((int) a) << (int) b; }
629 };
630
632 {
633 RightShiftOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::rightShift) {}
634 var getWithInts (int64 a, int64 b) const override { return ((int) a) >> (int) b; }
635 };
636
638 {
639 RightShiftUnsignedOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::rightShiftUnsigned) {}
640 var getWithInts (int64 a, int64 b) const override { return (int) (((uint32) a) >> (int) b); }
641 };
642
644 {
645 LogicalAndOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::logicalAnd) {}
646 var getResult (const Scope& s) const override { return lhs->getResult (s) && rhs->getResult (s); }
647 };
648
650 {
651 LogicalOrOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::logicalOr) {}
652 var getResult (const Scope& s) const override { return lhs->getResult (s) || rhs->getResult (s); }
653 };
654
656 {
657 TypeEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::typeEquals) {}
658 var getResult (const Scope& s) const override { return areTypeEqual (lhs->getResult (s), rhs->getResult (s)); }
659 };
660
662 {
663 TypeNotEqualsOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperatorBase (l, a, b, TokenTypes::typeNotEquals) {}
664 var getResult (const Scope& s) const override { return ! areTypeEqual (lhs->getResult (s), rhs->getResult (s)); }
665 };
666
668 {
669 ConditionalOp (const CodeLocation& l) noexcept : Expression (l) {}
670
671 var getResult (const Scope& s) const override { return (condition->getResult (s) ? trueBranch : falseBranch)->getResult (s); }
672 void assign (const Scope& s, const var& v) const override { (condition->getResult (s) ? trueBranch : falseBranch)->assign (s, v); }
673
674 ExpPtr condition, trueBranch, falseBranch;
675 };
676
678 {
679 Assignment (const CodeLocation& l, ExpPtr& dest, ExpPtr& source) noexcept : Expression (l), target (dest.release()), newValue (source.release()) {}
680
681 var getResult (const Scope& s) const override
682 {
683 auto value = newValue->getResult (s);
684 target->assign (s, value);
685 return value;
686 }
687
688 ExpPtr target, newValue;
689 };
690
692 {
693 SelfAssignment (const CodeLocation& l, Expression* dest, Expression* source) noexcept
694 : Expression (l), target (dest), newValue (source) {}
695
696 var getResult (const Scope& s) const override
697 {
698 auto value = newValue->getResult (s);
699 target->assign (s, value);
700 return value;
701 }
702
703 Expression* target; // Careful! this pointer aliases a sub-term of newValue!
704 ExpPtr newValue;
705 TokenType op;
706 };
707
709 {
710 PostAssignment (const CodeLocation& l, Expression* dest, Expression* source) noexcept : SelfAssignment (l, dest, source) {}
711
712 var getResult (const Scope& s) const override
713 {
714 auto oldValue = target->getResult (s);
715 target->assign (s, newValue->getResult (s));
716 return oldValue;
717 }
718 };
719
720 struct FunctionCall : public Expression
721 {
722 FunctionCall (const CodeLocation& l) noexcept : Expression (l) {}
723
724 var getResult (const Scope& s) const override
725 {
726 if (auto* dot = dynamic_cast<DotOperator*> (object.get()))
727 {
728 auto thisObject = dot->parent->getResult (s);
729 return invokeFunction (s, s.findFunctionCall (location, thisObject, dot->child), thisObject);
730 }
731
732 auto function = object->getResult (s);
733 return invokeFunction (s, function, var (s.scope.get()));
734 }
735
736 var invokeFunction (const Scope& s, const var& function, const var& thisObject) const
737 {
738 s.checkTimeOut (location);
739 Array<var> argVars;
740
741 for (auto* a : arguments)
742 argVars.add (a->getResult (s));
743
744 const var::NativeFunctionArgs args (thisObject, argVars.begin(), argVars.size());
745
746 if (var::NativeFunction nativeFunction = function.getNativeFunction())
747 return nativeFunction (args);
748
749 if (auto* fo = dynamic_cast<FunctionObject*> (function.getObject()))
750 return fo->invoke (s, args);
751
752 if (auto* dot = dynamic_cast<DotOperator*> (object.get()))
753 if (auto* o = thisObject.getDynamicObject())
754 if (o->hasMethod (dot->child)) // allow an overridden DynamicObject::invokeMethod to accept a method call.
755 return o->invokeMethod (dot->child, args);
756
757 location.throwError ("This expression is not a function!"); return {};
758 }
759
760 ExpPtr object;
761 OwnedArray<Expression> arguments;
762 };
763
765 {
766 NewOperator (const CodeLocation& l) noexcept : FunctionCall (l) {}
767
768 var getResult (const Scope& s) const override
769 {
770 var classOrFunc = object->getResult (s);
771 const bool isFunc = isFunction (classOrFunc);
772
773 if (! (isFunc || classOrFunc.getDynamicObject() != nullptr))
774 return var::undefined();
775
776 DynamicObject::Ptr newObject (new DynamicObject());
777
778 if (isFunc)
779 invokeFunction (s, classOrFunc, newObject.get());
780 else
781 newObject->setProperty (getPrototypeIdentifier(), classOrFunc);
782
783 return newObject.get();
784 }
785 };
786
788 {
789 ObjectDeclaration (const CodeLocation& l) noexcept : Expression (l) {}
790
791 var getResult (const Scope& s) const override
792 {
793 DynamicObject::Ptr newObject (new DynamicObject());
794
795 for (int i = 0; i < names.size(); ++i)
796 newObject->setProperty (names.getUnchecked (i), initialisers.getUnchecked (i)->getResult (s));
797
798 return newObject.get();
799 }
800
801 Array<Identifier> names;
802 OwnedArray<Expression> initialisers;
803 };
804
806 {
807 ArrayDeclaration (const CodeLocation& l) noexcept : Expression (l) {}
808
809 var getResult (const Scope& s) const override
810 {
811 Array<var> a;
812
813 for (int i = 0; i < values.size(); ++i)
814 a.add (values.getUnchecked (i)->getResult (s));
815
816 // std::move() needed here for older compilers
817 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move")
818 return std::move (a);
819 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
820 }
821
823 };
824
825 //==============================================================================
827 {
828 FunctionObject() noexcept {}
829
830 FunctionObject (const FunctionObject& other) : DynamicObject(), functionCode (other.functionCode)
831 {
832 ExpressionTreeBuilder tb (functionCode);
833 tb.parseFunctionParamsAndBody (*this);
834 }
835
836 std::unique_ptr<DynamicObject> clone() const override { return std::make_unique<FunctionObject> (*this); }
837
838 void writeAsJSON (OutputStream& out, const JSON::FormatOptions&) override
839 {
840 out << "function " << functionCode;
841 }
842
843 var invoke (const Scope& s, const var::NativeFunctionArgs& args) const
844 {
845 DynamicObject::Ptr functionRoot (new DynamicObject());
846
847 static const Identifier thisIdent ("this");
848 functionRoot->setProperty (thisIdent, args.thisObject);
849
850 for (int i = 0; i < parameters.size(); ++i)
851 functionRoot->setProperty (parameters.getReference (i),
852 i < args.numArguments ? args.arguments[i] : var::undefined());
853
854 var result;
855 body->perform (Scope (&s, s.root, functionRoot), &result);
856 return result;
857 }
858
859 String functionCode;
860 Array<Identifier> parameters;
862 };
863
864 //==============================================================================
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 {
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 //==============================================================================
1060 {
1061 ExpressionTreeBuilder (const String code) : TokenIterator (code) {}
1062
1063 BlockStatement* parseStatementList()
1064 {
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 {
1180 s->name = parseIdentifier();
1181 s->initialiser.reset (matchIf (TokenTypes::assign) ? parseExpression() : new Expression (location));
1182
1183 if (matchIf (TokenTypes::comma))
1184 {
1185 std::unique_ptr<BlockStatement> block (new BlockStatement (location));
1186 block->statements.add (std::move (s));
1187 block->statements.add (parseVar());
1188 return block.release();
1189 }
1190
1191 match (TokenTypes::semicolon);
1192 return s.release();
1193 }
1194
1195 Statement* parseFunction()
1196 {
1197 Identifier name;
1198 auto fn = parseFunctionDefinition (name);
1199
1200 if (name.isNull())
1201 throwError ("Functions defined at statement-level must have a name");
1202
1203 ExpPtr nm (new UnqualifiedName (location, name)), value (new LiteralValue (location, fn));
1204 return new Assignment (location, nm, value);
1205 }
1206
1207 Statement* parseForLoop()
1208 {
1209 std::unique_ptr<LoopStatement> s (new LoopStatement (location, false));
1210 match (TokenTypes::openParen);
1211 s->initialiser.reset (parseStatement());
1212
1213 if (matchIf (TokenTypes::semicolon))
1214 s->condition.reset (new LiteralValue (location, true));
1215 else
1216 {
1217 s->condition.reset (parseExpression());
1218 match (TokenTypes::semicolon);
1219 }
1220
1221 if (matchIf (TokenTypes::closeParen))
1222 s->iterator.reset (new Statement (location));
1223 else
1224 {
1225 s->iterator.reset (parseExpression());
1226 match (TokenTypes::closeParen);
1227 }
1228
1229 s->body.reset (parseStatement());
1230 return s.release();
1231 }
1232
1233 Statement* parseDoOrWhileLoop (bool isDoLoop)
1234 {
1235 std::unique_ptr<LoopStatement> s (new LoopStatement (location, isDoLoop));
1236 s->initialiser.reset (new Statement (location));
1237 s->iterator.reset (new Statement (location));
1238
1239 if (isDoLoop)
1240 {
1241 s->body.reset (parseBlock());
1242 match (TokenTypes::while_);
1243 }
1244
1245 match (TokenTypes::openParen);
1246 s->condition.reset (parseExpression());
1247 match (TokenTypes::closeParen);
1248
1249 if (! isDoLoop)
1250 s->body.reset (parseStatement());
1251
1252 return s.release();
1253 }
1254
1255 Identifier parseIdentifier()
1256 {
1257 Identifier i;
1258 if (currentType == TokenTypes::identifier)
1259 i = currentValue.toString();
1260
1261 match (TokenTypes::identifier);
1262 return i;
1263 }
1264
1265 var parseFunctionDefinition (Identifier& functionName)
1266 {
1267 auto functionStart = location.location;
1268
1269 if (currentType == TokenTypes::identifier)
1270 functionName = parseIdentifier();
1271
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 {
1281 s->object = std::move (function);
1282 match (TokenTypes::openParen);
1283
1284 while (currentType != TokenTypes::closeParen)
1285 {
1286 s->arguments.add (parseExpression());
1287 if (currentType != TokenTypes::closeParen)
1288 match (TokenTypes::comma);
1289 }
1290
1291 return matchCloseParen (s.release());
1292 }
1293
1294 Expression* parseSuffixes (Expression* e)
1295 {
1296 ExpPtr input (e);
1297
1298 if (matchIf (TokenTypes::dot))
1299 return parseSuffixes (new DotOperator (location, input, parseIdentifier()));
1300
1301 if (currentType == TokenTypes::openParen)
1302 return parseSuffixes (parseFunctionCall (new FunctionCall (location), input));
1303
1304 if (matchIf (TokenTypes::openBracket))
1305 {
1307 s->object = std::move (input);
1308 s->index.reset (parseExpression());
1309 match (TokenTypes::closeBracket);
1310 return parseSuffixes (s.release());
1311 }
1312
1313 if (matchIf (TokenTypes::plusplus)) return parsePostIncDec<AdditionOp> (input);
1314 if (matchIf (TokenTypes::minusminus)) return parsePostIncDec<SubtractionOp> (input);
1315
1316 return input.release();
1317 }
1318
1319 Expression* parseFactor()
1320 {
1321 if (currentType == TokenTypes::identifier) return parseSuffixes (new UnqualifiedName (location, parseIdentifier()));
1322 if (matchIf (TokenTypes::openParen)) return parseSuffixes (matchCloseParen (parseExpression()));
1323 if (matchIf (TokenTypes::true_)) return parseSuffixes (new LiteralValue (location, (int) 1));
1324 if (matchIf (TokenTypes::false_)) return parseSuffixes (new LiteralValue (location, (int) 0));
1325 if (matchIf (TokenTypes::null_)) return parseSuffixes (new LiteralValue (location, var()));
1326 if (matchIf (TokenTypes::undefined)) return parseSuffixes (new Expression (location));
1327
1328 if (currentType == TokenTypes::literal)
1329 {
1330 var v (currentValue); skip();
1331 return parseSuffixes (new LiteralValue (location, v));
1332 }
1333
1334 if (matchIf (TokenTypes::openBrace))
1335 {
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 {
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 {
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 {
1516 e->condition = std::move (condition);
1517 e->trueBranch.reset (parseExpression());
1518 match (TokenTypes::colon);
1519 e->falseBranch.reset (parseExpression());
1520 return e.release();
1521 }
1522
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 //==============================================================================
1535 {
1536 ObjectClass()
1537 {
1538 setMethod ("dump", dump);
1539 setMethod ("clone", cloneFn);
1540 }
1541
1542 static Identifier getClassName() { static const Identifier i ("Object"); return i; }
1543 static var dump ([[maybe_unused]] Args a) { DBG (JSON::toString (a.thisObject)); return var::undefined(); }
1544 static var cloneFn (Args a) { return a.thisObject.clone(); }
1545 };
1546
1547 //==============================================================================
1549 {
1550 ArrayClass()
1551 {
1552 setMethod ("contains", contains);
1553 setMethod ("remove", remove);
1554 setMethod ("join", join);
1555 setMethod ("push", push);
1556 setMethod ("splice", splice);
1557 setMethod ("indexOf", indexOf);
1558 }
1559
1560 static Identifier getClassName() { static const Identifier i ("Array"); return i; }
1561
1562 static var contains (Args a)
1563 {
1564 if (auto* array = a.thisObject.getArray())
1565 return array->contains (get (a, 0));
1566
1567 return false;
1568 }
1569
1570 static var remove (Args a)
1571 {
1572 if (auto* array = a.thisObject.getArray())
1573 array->removeAllInstancesOf (get (a, 0));
1574
1575 return var::undefined();
1576 }
1577
1578 static var join (Args a)
1579 {
1580 StringArray strings;
1581
1582 if (auto* array = a.thisObject.getArray())
1583 for (auto& v : *array)
1584 strings.add (v.toString());
1585
1586 return strings.joinIntoString (getString (a, 0));
1587 }
1588
1589 static var push (Args a)
1590 {
1591 if (auto* array = a.thisObject.getArray())
1592 {
1593 for (int i = 0; i < a.numArguments; ++i)
1594 array->add (a.arguments[i]);
1595
1596 return array->size();
1597 }
1598
1599 return var::undefined();
1600 }
1601
1602 static var splice (Args a)
1603 {
1604 if (auto* array = a.thisObject.getArray())
1605 {
1606 auto arraySize = array->size();
1607 int start = get (a, 0);
1608
1609 if (start < 0)
1610 start = jmax (0, arraySize + start);
1611 else if (start > arraySize)
1612 start = arraySize;
1613
1614 const int num = a.numArguments > 1 ? jlimit (0, arraySize - start, getInt (a, 1))
1615 : arraySize - start;
1616
1617 Array<var> itemsRemoved;
1618 itemsRemoved.ensureStorageAllocated (num);
1619
1620 for (int i = 0; i < num; ++i)
1621 itemsRemoved.add (array->getReference (start + i));
1622
1623 array->removeRange (start, num);
1624
1625 for (int i = 2; i < a.numArguments; ++i)
1626 array->insert (start++, get (a, i));
1627
1628 // std::move() needed here for older compilers
1629 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move")
1630 return std::move (itemsRemoved);
1631 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1632 }
1633
1634 return var::undefined();
1635 }
1636
1637 static var indexOf (Args a)
1638 {
1639 if (auto* array = a.thisObject.getArray())
1640 {
1641 auto target = get (a, 0);
1642
1643 for (int i = (a.numArguments > 1 ? getInt (a, 1) : 0); i < array->size(); ++i)
1644 if (array->getReference (i) == target)
1645 return i;
1646 }
1647
1648 return -1;
1649 }
1650 };
1651
1652 //==============================================================================
1654 {
1655 StringClass()
1656 {
1657 setMethod ("substring", substring);
1658 setMethod ("indexOf", indexOf);
1659 setMethod ("charAt", charAt);
1660 setMethod ("charCodeAt", charCodeAt);
1661 setMethod ("fromCharCode", fromCharCode);
1662 setMethod ("split", split);
1663 }
1664
1665 static Identifier getClassName() { static const Identifier i ("String"); return i; }
1666
1667 static var fromCharCode (Args a) { return String::charToString (static_cast<juce_wchar> (getInt (a, 0))); }
1668 static var substring (Args a) { return a.thisObject.toString().substring (getInt (a, 0), getInt (a, 1)); }
1669 static var indexOf (Args a) { return a.thisObject.toString().indexOf (getString (a, 0)); }
1670 static var charCodeAt (Args a) { return (int) a.thisObject.toString() [getInt (a, 0)]; }
1671 static var charAt (Args a) { int p = getInt (a, 0); return a.thisObject.toString().substring (p, p + 1); }
1672
1673 static var split (Args a)
1674 {
1675 auto str = a.thisObject.toString();
1676 auto sep = getString (a, 0);
1677 StringArray strings;
1678
1679 if (sep.isNotEmpty())
1680 strings.addTokens (str, sep.substring (0, 1), {});
1681 else // special-case for empty separator: split all chars separately
1682 for (auto pos = str.getCharPointer(); ! pos.isEmpty(); ++pos)
1683 strings.add (String::charToString (*pos));
1684
1685 var array;
1686
1687 for (auto& s : strings)
1688 array.append (s);
1689
1690 return array;
1691 }
1692 };
1693
1694 //==============================================================================
1696 {
1697 MathClass()
1698 {
1699 setMethod ("abs", Math_abs); setMethod ("round", Math_round);
1700 setMethod ("random", Math_random); setMethod ("randInt", Math_randInt);
1701 setMethod ("min", Math_min); setMethod ("max", Math_max);
1702 setMethod ("range", Math_range); setMethod ("sign", Math_sign);
1703 setMethod ("toDegrees", Math_toDegrees); setMethod ("toRadians", Math_toRadians);
1704 setMethod ("sin", Math_sin); setMethod ("asin", Math_asin);
1705 setMethod ("sinh", Math_sinh); setMethod ("asinh", Math_asinh);
1706 setMethod ("cos", Math_cos); setMethod ("acos", Math_acos);
1707 setMethod ("cosh", Math_cosh); setMethod ("acosh", Math_acosh);
1708 setMethod ("tan", Math_tan); setMethod ("atan", Math_atan);
1709 setMethod ("tanh", Math_tanh); setMethod ("atanh", Math_atanh);
1710 setMethod ("log", Math_log); setMethod ("log10", Math_log10);
1711 setMethod ("exp", Math_exp); setMethod ("pow", Math_pow);
1712 setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt);
1713 setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor);
1714 setMethod ("hypot", Math_hypot);
1715
1716 setProperty ("PI", MathConstants<double>::pi);
1717 setProperty ("E", MathConstants<double>::euler);
1718 setProperty ("SQRT2", MathConstants<double>::sqrt2);
1719 setProperty ("SQRT1_2", std::sqrt (0.5));
1720 setProperty ("LN2", std::log (2.0));
1721 setProperty ("LN10", std::log (10.0));
1722 setProperty ("LOG2E", std::log (MathConstants<double>::euler) / std::log (2.0));
1723 setProperty ("LOG10E", std::log (MathConstants<double>::euler) / std::log (10.0));
1724 }
1725
1726 static var Math_random (Args) { return Random::getSystemRandom().nextDouble(); }
1727 static var Math_randInt (Args a) { return Random::getSystemRandom().nextInt (Range<int> (getInt (a, 0), getInt (a, 1))); }
1728 static var Math_abs (Args a) { return isInt (a, 0) ? var (std::abs (getInt (a, 0))) : var (std::abs (getDouble (a, 0))); }
1729 static var Math_round (Args a) { return isInt (a, 0) ? var (roundToInt (getInt (a, 0))) : var (roundToInt (getDouble (a, 0))); }
1730 static var Math_sign (Args a) { return isInt (a, 0) ? var (sign (getInt (a, 0))) : var (sign (getDouble (a, 0))); }
1731 static var Math_range (Args a) { return isInt (a, 0) ? var (jlimit (getInt (a, 1), getInt (a, 2), getInt (a, 0))) : var (jlimit (getDouble (a, 1), getDouble (a, 2), getDouble (a, 0))); }
1732 static var Math_min (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmin (getInt (a, 0), getInt (a, 1))) : var (jmin (getDouble (a, 0), getDouble (a, 1))); }
1733 static var Math_max (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmax (getInt (a, 0), getInt (a, 1))) : var (jmax (getDouble (a, 0), getDouble (a, 1))); }
1734 static var Math_toDegrees (Args a) { return radiansToDegrees (getDouble (a, 0)); }
1735 static var Math_toRadians (Args a) { return degreesToRadians (getDouble (a, 0)); }
1736 static var Math_sin (Args a) { return std::sin (getDouble (a, 0)); }
1737 static var Math_asin (Args a) { return std::asin (getDouble (a, 0)); }
1738 static var Math_cos (Args a) { return std::cos (getDouble (a, 0)); }
1739 static var Math_acos (Args a) { return std::acos (getDouble (a, 0)); }
1740 static var Math_sinh (Args a) { return std::sinh (getDouble (a, 0)); }
1741 static var Math_cosh (Args a) { return std::cosh (getDouble (a, 0)); }
1742 static var Math_tan (Args a) { return std::tan (getDouble (a, 0)); }
1743 static var Math_tanh (Args a) { return std::tanh (getDouble (a, 0)); }
1744 static var Math_atan (Args a) { return std::atan (getDouble (a, 0)); }
1745 static var Math_log (Args a) { return std::log (getDouble (a, 0)); }
1746 static var Math_log10 (Args a) { return std::log10 (getDouble (a, 0)); }
1747 static var Math_exp (Args a) { return std::exp (getDouble (a, 0)); }
1748 static var Math_pow (Args a) { return std::pow (getDouble (a, 0), getDouble (a, 1)); }
1749 static var Math_sqr (Args a) { return square (getDouble (a, 0)); }
1750 static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); }
1751 static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); }
1752 static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); }
1753 static var Math_hypot (Args a) { return std::hypot (getDouble (a, 0), getDouble (a, 1)); }
1754
1755 // We can't use the std namespace equivalents of these functions without breaking
1756 // compatibility with older versions of OS X.
1757 static var Math_asinh (Args a) { return asinh (getDouble (a, 0)); }
1758 static var Math_acosh (Args a) { return acosh (getDouble (a, 0)); }
1759 static var Math_atanh (Args a) { return atanh (getDouble (a, 0)); }
1760
1761 static Identifier getClassName() { static const Identifier i ("Math"); return i; }
1762 template <typename Type> static Type sign (Type n) noexcept { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
1763 };
1764
1765 //==============================================================================
1767 {
1768 JSONClass() { setMethod ("stringify", stringify); }
1769 static Identifier getClassName() { static const Identifier i ("JSON"); return i; }
1770 static var stringify (Args a) { return JSON::toString (get (a, 0)); }
1771 };
1772
1773 //==============================================================================
1775 {
1776 IntegerClass() { setMethod ("parseInt", parseInt); }
1777 static Identifier getClassName() { static const Identifier i ("Integer"); return i; }
1778
1779 static var parseInt (Args a)
1780 {
1781 auto s = getString (a, 0).trim();
1782
1783 return s[0] == '0' ? (s[1] == 'x' ? s.substring (2).getHexValue64() : getOctalValue (s))
1784 : s.getLargeIntValue();
1785 }
1786 };
1787
1788 //==============================================================================
1789 static var trace (Args a) { Logger::outputDebugString (JSON::toString (a.thisObject)); return var::undefined(); }
1790 static var charToInt (Args a) { return (int) (getString (a, 0)[0]); }
1791 static var parseFloat (Args a) { return getDouble (a, 0); }
1792
1793 static var typeof_internal (Args a)
1794 {
1795 var v (get (a, 0));
1796
1797 if (v.isVoid()) return "void";
1798 if (v.isString()) return "string";
1799 if (isNumeric (v)) return "number";
1800 if (isFunction (v) || v.isMethod()) return "function";
1801 if (v.isObject()) return "object";
1802
1803 return "undefined";
1804 }
1805
1806 static var exec (Args a)
1807 {
1808 if (auto* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
1809 root->execute (getString (a, 0));
1810
1811 return var::undefined();
1812 }
1813
1814 static var eval (Args a)
1815 {
1816 if (auto* root = dynamic_cast<RootObject*> (a.thisObject.getObject()))
1817 return root->evaluate (getString (a, 0));
1818
1819 return var::undefined();
1820 }
1821};
1822
1823//==============================================================================
1824JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new RootObject())
1825{
1826 registerNativeObject (RootObject::ObjectClass ::getClassName(), new RootObject::ObjectClass());
1827 registerNativeObject (RootObject::ArrayClass ::getClassName(), new RootObject::ArrayClass());
1828 registerNativeObject (RootObject::StringClass ::getClassName(), new RootObject::StringClass());
1829 registerNativeObject (RootObject::MathClass ::getClassName(), new RootObject::MathClass());
1830 registerNativeObject (RootObject::JSONClass ::getClassName(), new RootObject::JSONClass());
1831 registerNativeObject (RootObject::IntegerClass ::getClassName(), new RootObject::IntegerClass());
1832}
1833
1835
1836void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
1837void JavascriptEngine::stop() noexcept { root->timeout = {}; }
1838
1840{
1841 root->setProperty (name, object);
1842}
1843
1845{
1846 try
1847 {
1848 prepareTimeout();
1849 root->execute (code);
1850 }
1851 catch (String& error)
1852 {
1853 return Result::fail (error);
1854 }
1855
1856 return Result::ok();
1857}
1858
1860{
1861 try
1862 {
1863 prepareTimeout();
1864 if (result != nullptr) *result = Result::ok();
1865 return root->evaluate (code);
1866 }
1867 catch (String& error)
1868 {
1869 if (result != nullptr) *result = Result::fail (error);
1870 }
1871
1872 return var::undefined();
1873}
1874
1876{
1877 auto returnVal = var::undefined();
1878
1879 try
1880 {
1881 prepareTimeout();
1882 if (result != nullptr) *result = Result::ok();
1883 RootObject::Scope ({}, *root, *root).findAndInvokeMethod (function, args, returnVal);
1884 }
1885 catch (String& error)
1886 {
1887 if (result != nullptr) *result = Result::fail (error);
1888 }
1889
1890 return returnVal;
1891}
1892
1894 const var::NativeFunctionArgs& args, Result* result)
1895{
1896 auto returnVal = var::undefined();
1897
1898 try
1899 {
1900 prepareTimeout();
1901 if (result != nullptr) *result = Result::ok();
1902 RootObject::Scope rootScope ({}, *root, *root);
1904 .invokeMethod (functionObject, args, returnVal);
1905 }
1906 catch (String& error)
1907 {
1908 if (result != nullptr) *result = Result::fail (error);
1909 }
1910
1911 return returnVal;
1912}
1913
1915{
1916 return root->getProperties();
1917}
1918
1919JUCE_END_IGNORE_WARNINGS_MSVC
1920
1921} // namespace juce
T acos(T... args)
acosh
T asin(T... args)
asinh
T atan(T... args)
atanh
T ceil(T... args)
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
void ensureStorageAllocated(int minNumElements)
Increases the array's internal storage to hold a minimum number of elements.
int size() const noexcept
Returns the current number of elements in the array.
Definition juce_Array.h:215
ElementType * begin() noexcept
Returns a pointer to the first element in the array.
Definition juce_Array.h:328
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition juce_Array.h:418
An arbitrarily large integer class.
void parseString(StringRef text, int base)
Reads the numeric value from a string.
int64 toInt64() const noexcept
Attempts to get the lowest 64 bits of the value as an integer.
Wraps a pointer to a null-terminated ASCII character string, and provides various methods to operate ...
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
int compareUpTo(const CharPointer other, const int maxChars) const noexcept
Compares this string with another one, up to a specified number of characters.
void incrementToEndOfWhitespace() noexcept
Move this pointer to the first non-whitespace character in the string.
bool isEmpty() const noexcept
Returns true if this pointer is pointing to a null character.
bool isDigit() const noexcept
Returns true if the first character of this string is a digit.
Represents a dynamically implemented object.
NamedValueSet & getProperties() noexcept
Returns the NamedValueSet that holds the object's properties.
virtual var invokeMethod(Identifier methodName, const var::NativeFunctionArgs &args)
Invokes a named method on this object.
virtual bool hasMethod(const Identifier &methodName) const
Checks whether this object has the specified method.
virtual const var & getProperty(const Identifier &propertyName) const
Returns a named property.
virtual void setProperty(const Identifier &propertyName, const var &newValue)
Sets a named property.
Represents a string identifier, designed for accessing properties by name.
bool isNull() const noexcept
Returns true if this Identifier is null.
String::CharPointerType getCharPointer() const noexcept
Returns this identifier's raw string pointer.
bool isValid() const noexcept
Returns true if this Identifier is not null.
const String & toString() const noexcept
Returns this identifier as a string.
Allows formatting var objects as JSON with various configurable options.
Definition juce_JSON.h:102
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.
A simple javascript interpreter!
void stop() noexcept
When called from another thread, causes the interpreter to time-out as soon as possible.
const NamedValueSet & getRootObjectProperties() const noexcept
Provides access to the set of properties of the root namespace object.
Result execute(const String &javascriptCode)
Attempts to parse and run a block of javascript code.
var callFunction(const Identifier &function, const var::NativeFunctionArgs &args, Result *errorMessage=nullptr)
Calls a function in the root namespace, and returns the result.
var evaluate(const String &javascriptCode, Result *errorMessage=nullptr)
Attempts to parse and run a javascript expression, and returns the result.
void registerNativeObject(const Identifier &objectName, DynamicObject *object)
Adds a native object to the root namespace.
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.
JavascriptEngine()
Creates an instance of the engine.
RelativeTime maximumExecutionTime
This value indicates how long a call to one of the evaluate methods is permitted to run before timing...
static void JUCE_CALLTYPE outputDebugString(const String &text)
Writes a message to the standard error stream.
Holds a set of named var objects.
The base class for streams that write data to some kind of destination.
An array designed for holding objects.
A general-purpose range object, that simply represents any linear range with a start and end point.
Definition juce_Range.h:40
A smart-pointer class which points to a reference-counted object.
ReferencedType * get() const noexcept
Returns the object that this pointer references.
Represents the 'success' or 'failure' of an operation, and holds an associated error message to descr...
Definition juce_Result.h:57
static Result fail(const String &errorMessage) noexcept
Creates a 'failure' result.
static Result ok() noexcept
Creates and returns a 'successful' result.
Definition juce_Result.h:61
A special array for holding a list of strings.
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
Joins the strings in the array together into one string.
void add(String stringToAdd)
Appends a string at the end of the array.
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Breaks up a string into tokens and adds them to this array.
The JUCE String class!
Definition juce_String.h:53
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
int indexOf(StringRef textToLookFor) const noexcept
Searches for a substring within this string.
String initialSectionContainingOnly(StringRef permittedCharacters) const
Returns a section from the start of the string that only contains a certain set of characters.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
Holds an absolute date and time.
Definition juce_Time.h:37
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
A variant class, that can be used to hold a range of primitive values.
static var undefined() noexcept
Returns a var object that can be used where you need the javascript "undefined" value.
int size() const
If the var is an array, this returns the number of elements.
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.
void append(const var &valueToAppend)
Appends an element to the var, converting it to an array if it isn't already one.
bool hasSameTypeAs(const var &other) const noexcept
Returns true if this var has the same type as the one supplied.
var clone() const noexcept
Returns a deep copy of this object.
T cos(T... args)
T cosh(T... args)
T exp(T... args)
T floor(T... args)
fmod
T get(T... args)
T hypot(T... args)
T infinity(T... args)
#define DBG(textToWrite)
Writes a string to the standard error stream.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
auto & get(ProcessorChain< Processors... > &chain) noexcept
Non-member equivalent of ProcessorChain::get which avoids awkward member template syntax.
typedef int
T log10(T... args)
T log(T... args)
JUCE Namespace.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr bool exactlyEqual(Type a, Type b)
Equivalent to operator==, but suppresses float-equality warnings.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
constexpr NumericType square(NumericType n) noexcept
Returns the square of its argument.
constexpr FloatType radiansToDegrees(FloatType radians) noexcept
Converts an angle in radians to degrees.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
constexpr FloatType degreesToRadians(FloatType degrees) noexcept
Converts an angle in degrees to radians.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
long long int64
A platform-independent 64-bit integer type.
T pow(T... args)
T release(T... args)
remove
T reset(T... args)
T sin(T... args)
T sinh(T... args)
T sqrt(T... args)
void writeAsJSON(OutputStream &out, const JSON::FormatOptions &) override
Writes this object to a text stream in JSON format.
std::unique_ptr< DynamicObject > clone() const override
Returns a clone of this object.
Commonly used mathematical constants.
This structure is passed to a NativeFunction callback, and contains invocation details about the func...
typedef size_t
T tan(T... args)
T tanh(T... args)