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