Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/Function.h>
28#include <AK/HashMap.h>
29#include <AK/ScopeGuard.h>
30#include <AK/StringBuilder.h>
31#include <LibJS/AST.h>
32#include <LibJS/Interpreter.h>
33#include <LibJS/Runtime/Array.h>
34#include <LibJS/Runtime/Error.h>
35#include <LibJS/Runtime/GlobalObject.h>
36#include <LibJS/Runtime/NativeFunction.h>
37#include <LibJS/Runtime/PrimitiveString.h>
38#include <LibJS/Runtime/ScriptFunction.h>
39#include <LibJS/Runtime/Value.h>
40#include <stdio.h>
41
42namespace JS {
43
44Value ScopeNode::execute(Interpreter& interpreter) const
45{
46 return interpreter.run(*this);
47}
48
49Value FunctionDeclaration::execute(Interpreter& interpreter) const
50{
51 auto* function = interpreter.heap().allocate<ScriptFunction>(body(), parameters());
52 interpreter.set_variable(name(), function);
53 return js_undefined();
54}
55
56Value FunctionExpression::execute(Interpreter& interpreter) const
57{
58 return interpreter.heap().allocate<ScriptFunction>(body(), parameters());
59}
60
61Value ExpressionStatement::execute(Interpreter& interpreter) const
62{
63 return m_expression->execute(interpreter);
64}
65
66CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interpreter& interpreter) const
67{
68 if (is_new_expression()) {
69 // Computing |this| is irrelevant for "new" expression.
70 return { js_undefined(), m_callee->execute(interpreter) };
71 }
72
73 if (m_callee->is_member_expression()) {
74 auto& member_expression = static_cast<const MemberExpression&>(*m_callee);
75 auto object_value = member_expression.object().execute(interpreter);
76 if (interpreter.exception())
77 return {};
78 auto* this_value = object_value.to_object(interpreter.heap());
79 if (interpreter.exception())
80 return {};
81 auto callee = this_value->get(member_expression.computed_property_name(interpreter)).value_or(js_undefined());
82 return { this_value, callee };
83 }
84 return { &interpreter.global_object(), m_callee->execute(interpreter) };
85}
86
87Value CallExpression::execute(Interpreter& interpreter) const
88{
89 auto [this_value, callee] = compute_this_and_callee(interpreter);
90 if (interpreter.exception())
91 return {};
92
93 ASSERT(!callee.is_empty());
94
95 if (is_new_expression()) {
96 if (!callee.is_object()
97 || !callee.as_object().is_function()
98 || (callee.as_object().is_native_function()
99 && !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))
100 return interpreter.throw_exception<Error>("TypeError", String::format("%s is not a constructor", callee.to_string().characters()));
101 }
102
103 if (!callee.is_object() || !callee.as_object().is_function())
104 return interpreter.throw_exception<Error>("TypeError", String::format("%s is not a function", callee.to_string().characters()));
105
106 auto& function = static_cast<Function&>(callee.as_object());
107
108 Vector<Value> arguments;
109 arguments.ensure_capacity(m_arguments.size());
110 for (size_t i = 0; i < m_arguments.size(); ++i) {
111 auto value = m_arguments[i].execute(interpreter);
112 if (interpreter.exception())
113 return {};
114 arguments.append(value);
115 if (interpreter.exception())
116 return {};
117 }
118
119 auto& call_frame = interpreter.push_call_frame();
120 call_frame.arguments = move(arguments);
121
122 Object* new_object = nullptr;
123 Value result;
124 if (is_new_expression()) {
125 new_object = interpreter.heap().allocate<Object>();
126 auto prototype = function.get("prototype");
127 if (prototype.has_value() && prototype.value().is_object())
128 new_object->set_prototype(&prototype.value().as_object());
129 call_frame.this_value = new_object;
130 result = function.construct(interpreter);
131 } else {
132 call_frame.this_value = this_value;
133 result = function.call(interpreter);
134 }
135
136 if (interpreter.exception())
137 return {};
138
139 interpreter.pop_call_frame();
140
141 if (is_new_expression()) {
142 if (result.is_object())
143 return result;
144 return new_object;
145 }
146 return result;
147}
148
149Value ReturnStatement::execute(Interpreter& interpreter) const
150{
151 auto value = argument() ? argument()->execute(interpreter) : js_undefined();
152 if (interpreter.exception())
153 return {};
154 interpreter.unwind(ScopeType::Function);
155 return value;
156}
157
158Value IfStatement::execute(Interpreter& interpreter) const
159{
160 auto predicate_result = m_predicate->execute(interpreter);
161 if (interpreter.exception())
162 return {};
163
164 if (predicate_result.to_boolean())
165 return interpreter.run(*m_consequent);
166
167 if (m_alternate)
168 return interpreter.run(*m_alternate);
169
170 return js_undefined();
171}
172
173Value WhileStatement::execute(Interpreter& interpreter) const
174{
175 Value last_value = js_undefined();
176 while (m_test->execute(interpreter).to_boolean()) {
177 if (interpreter.exception())
178 return {};
179 last_value = interpreter.run(*m_body);
180 if (interpreter.exception())
181 return {};
182 }
183
184 return last_value;
185}
186
187Value DoWhileStatement::execute(Interpreter& interpreter) const
188{
189 Value last_value = js_undefined();
190 do {
191 if (interpreter.exception())
192 return {};
193 last_value = interpreter.run(*m_body);
194 if (interpreter.exception())
195 return {};
196 } while (m_test->execute(interpreter).to_boolean());
197
198 return last_value;
199}
200
201Value ForStatement::execute(Interpreter& interpreter) const
202{
203 RefPtr<BlockStatement> wrapper;
204
205 if (m_init && m_init->is_variable_declaration() && static_cast<const VariableDeclaration*>(m_init.ptr())->declaration_kind() != DeclarationKind::Var) {
206 wrapper = create_ast_node<BlockStatement>();
207 interpreter.enter_scope(*wrapper, {}, ScopeType::Block);
208 }
209
210 auto wrapper_cleanup = ScopeGuard([&] {
211 if (wrapper)
212 interpreter.exit_scope(*wrapper);
213 });
214
215 Value last_value = js_undefined();
216
217 if (m_init) {
218 m_init->execute(interpreter);
219 if (interpreter.exception())
220 return {};
221 }
222
223 if (m_test) {
224 while (m_test->execute(interpreter).to_boolean()) {
225 if (interpreter.exception())
226 return {};
227 last_value = interpreter.run(*m_body);
228 if (interpreter.exception())
229 return {};
230 if (interpreter.should_unwind()) {
231 if (interpreter.should_unwind_until(ScopeType::Continuable)) {
232 interpreter.stop_unwind();
233 } else if (interpreter.should_unwind_until(ScopeType::Breakable)) {
234 interpreter.stop_unwind();
235 break;
236 } else {
237 return js_undefined();
238 }
239 }
240 if (m_update) {
241 m_update->execute(interpreter);
242 if (interpreter.exception())
243 return {};
244 }
245 }
246 } else {
247 while (true) {
248 last_value = interpreter.run(*m_body);
249 if (interpreter.exception())
250 return {};
251 if (interpreter.should_unwind()) {
252 if (interpreter.should_unwind_until(ScopeType::Continuable)) {
253 interpreter.stop_unwind();
254 } else if (interpreter.should_unwind_until(ScopeType::Breakable)) {
255 interpreter.stop_unwind();
256 break;
257 } else {
258 return js_undefined();
259 }
260 }
261 if (m_update) {
262 m_update->execute(interpreter);
263 if (interpreter.exception())
264 return {};
265 }
266 }
267 }
268
269 return last_value;
270}
271
272Value BinaryExpression::execute(Interpreter& interpreter) const
273{
274 auto lhs_result = m_lhs->execute(interpreter);
275 if (interpreter.exception())
276 return {};
277 auto rhs_result = m_rhs->execute(interpreter);
278 if (interpreter.exception())
279 return {};
280
281 switch (m_op) {
282 case BinaryOp::Addition:
283 return add(lhs_result, rhs_result);
284 case BinaryOp::Subtraction:
285 return sub(lhs_result, rhs_result);
286 case BinaryOp::Multiplication:
287 return mul(lhs_result, rhs_result);
288 case BinaryOp::Division:
289 return div(lhs_result, rhs_result);
290 case BinaryOp::Modulo:
291 return mod(lhs_result, rhs_result);
292 case BinaryOp::Exponentiation:
293 return exp(lhs_result, rhs_result);
294 case BinaryOp::TypedEquals:
295 return typed_eq(lhs_result, rhs_result);
296 case BinaryOp::TypedInequals:
297 return Value(!typed_eq(lhs_result, rhs_result).as_bool());
298 case BinaryOp::AbstractEquals:
299 return eq(lhs_result, rhs_result);
300 case BinaryOp::AbstractInequals:
301 return Value(!eq(lhs_result, rhs_result).as_bool());
302 case BinaryOp::GreaterThan:
303 return greater_than(lhs_result, rhs_result);
304 case BinaryOp::GreaterThanEquals:
305 return greater_than_equals(lhs_result, rhs_result);
306 case BinaryOp::LessThan:
307 return less_than(lhs_result, rhs_result);
308 case BinaryOp::LessThanEquals:
309 return less_than_equals(lhs_result, rhs_result);
310 case BinaryOp::BitwiseAnd:
311 return bitwise_and(lhs_result, rhs_result);
312 case BinaryOp::BitwiseOr:
313 return bitwise_or(lhs_result, rhs_result);
314 case BinaryOp::BitwiseXor:
315 return bitwise_xor(lhs_result, rhs_result);
316 case BinaryOp::LeftShift:
317 return left_shift(lhs_result, rhs_result);
318 case BinaryOp::RightShift:
319 return right_shift(lhs_result, rhs_result);
320 case BinaryOp::InstanceOf:
321 return instance_of(lhs_result, rhs_result);
322 }
323
324 ASSERT_NOT_REACHED();
325}
326
327Value LogicalExpression::execute(Interpreter& interpreter) const
328{
329 auto lhs_result = m_lhs->execute(interpreter);
330 if (interpreter.exception())
331 return {};
332
333 switch (m_op) {
334 case LogicalOp::And:
335 if (lhs_result.to_boolean()) {
336 auto rhs_result = m_rhs->execute(interpreter);
337 if (interpreter.exception())
338 return {};
339
340 return Value(rhs_result);
341 }
342
343 return Value(lhs_result);
344 case LogicalOp::Or:
345 if (lhs_result.to_boolean())
346 return Value(lhs_result);
347
348 auto rhs_result = m_rhs->execute(interpreter);
349 if (interpreter.exception())
350 return {};
351
352 return Value(rhs_result);
353 }
354
355 ASSERT_NOT_REACHED();
356}
357
358Value UnaryExpression::execute(Interpreter& interpreter) const
359{
360 auto lhs_result = m_lhs->execute(interpreter);
361 if (interpreter.exception())
362 return {};
363 switch (m_op) {
364 case UnaryOp::BitwiseNot:
365 return bitwise_not(lhs_result);
366 case UnaryOp::Not:
367 return Value(!lhs_result.to_boolean());
368 case UnaryOp::Plus:
369 return unary_plus(lhs_result);
370 case UnaryOp::Minus:
371 return unary_minus(lhs_result);
372 case UnaryOp::Typeof:
373 switch (lhs_result.type()) {
374 case Value::Type::Empty:
375 ASSERT_NOT_REACHED();
376 return {};
377 case Value::Type::Undefined:
378 return js_string(interpreter, "undefined");
379 case Value::Type::Null:
380 // yes, this is on purpose. yes, this is how javascript works.
381 // yes, it's silly.
382 return js_string(interpreter, "object");
383 case Value::Type::Number:
384 return js_string(interpreter, "number");
385 case Value::Type::String:
386 return js_string(interpreter, "string");
387 case Value::Type::Object:
388 if (lhs_result.as_object().is_function())
389 return js_string(interpreter, "function");
390 return js_string(interpreter, "object");
391 case Value::Type::Boolean:
392 return js_string(interpreter, "boolean");
393 }
394 }
395
396 ASSERT_NOT_REACHED();
397}
398
399static void print_indent(int indent)
400{
401 for (int i = 0; i < indent * 2; ++i)
402 putchar(' ');
403}
404
405void ASTNode::dump(int indent) const
406{
407 print_indent(indent);
408 printf("%s\n", class_name());
409}
410
411void ScopeNode::dump(int indent) const
412{
413 ASTNode::dump(indent);
414 for (auto& child : children())
415 child.dump(indent + 1);
416}
417
418void BinaryExpression::dump(int indent) const
419{
420 const char* op_string = nullptr;
421 switch (m_op) {
422 case BinaryOp::Addition:
423 op_string = "+";
424 break;
425 case BinaryOp::Subtraction:
426 op_string = "-";
427 break;
428 case BinaryOp::Multiplication:
429 op_string = "*";
430 break;
431 case BinaryOp::Division:
432 op_string = "/";
433 break;
434 case BinaryOp::Modulo:
435 op_string = "%";
436 break;
437 case BinaryOp::Exponentiation:
438 op_string = "**";
439 break;
440 case BinaryOp::TypedEquals:
441 op_string = "===";
442 break;
443 case BinaryOp::TypedInequals:
444 op_string = "!==";
445 break;
446 case BinaryOp::AbstractEquals:
447 op_string = "==";
448 break;
449 case BinaryOp::AbstractInequals:
450 op_string = "!=";
451 break;
452 case BinaryOp::GreaterThan:
453 op_string = ">";
454 break;
455 case BinaryOp::GreaterThanEquals:
456 op_string = ">=";
457 break;
458 case BinaryOp::LessThan:
459 op_string = "<";
460 break;
461 case BinaryOp::LessThanEquals:
462 op_string = "<=";
463 break;
464 case BinaryOp::BitwiseAnd:
465 op_string = "&";
466 break;
467 case BinaryOp::BitwiseOr:
468 op_string = "|";
469 break;
470 case BinaryOp::BitwiseXor:
471 op_string = "^";
472 break;
473 case BinaryOp::LeftShift:
474 op_string = "<<";
475 break;
476 case BinaryOp::RightShift:
477 op_string = ">>";
478 break;
479 case BinaryOp::InstanceOf:
480 op_string = "instanceof";
481 break;
482 }
483
484 print_indent(indent);
485 printf("%s\n", class_name());
486 m_lhs->dump(indent + 1);
487 print_indent(indent + 1);
488 printf("%s\n", op_string);
489 m_rhs->dump(indent + 1);
490}
491
492void LogicalExpression::dump(int indent) const
493{
494 const char* op_string = nullptr;
495 switch (m_op) {
496 case LogicalOp::And:
497 op_string = "&&";
498 break;
499 case LogicalOp::Or:
500 op_string = "||";
501 break;
502 }
503
504 print_indent(indent);
505 printf("%s\n", class_name());
506 m_lhs->dump(indent + 1);
507 print_indent(indent + 1);
508 printf("%s\n", op_string);
509 m_rhs->dump(indent + 1);
510}
511
512void UnaryExpression::dump(int indent) const
513{
514 const char* op_string = nullptr;
515 switch (m_op) {
516 case UnaryOp::BitwiseNot:
517 op_string = "~";
518 break;
519 case UnaryOp::Not:
520 op_string = "!";
521 break;
522 case UnaryOp::Plus:
523 op_string = "+";
524 break;
525 case UnaryOp::Minus:
526 op_string = "-";
527 break;
528 case UnaryOp::Typeof:
529 op_string = "typeof ";
530 break;
531 }
532
533 print_indent(indent);
534 printf("%s\n", class_name());
535 print_indent(indent + 1);
536 printf("%s\n", op_string);
537 m_lhs->dump(indent + 1);
538}
539
540void CallExpression::dump(int indent) const
541{
542 print_indent(indent);
543 printf("CallExpression %s\n", is_new_expression() ? "[new]" : "");
544 m_callee->dump(indent + 1);
545 for (auto& argument : m_arguments)
546 argument.dump(indent + 1);
547}
548
549void StringLiteral::dump(int indent) const
550{
551 print_indent(indent);
552 printf("StringLiteral \"%s\"\n", m_value.characters());
553}
554
555void NumericLiteral::dump(int indent) const
556{
557 print_indent(indent);
558 printf("NumericLiteral %g\n", m_value);
559}
560
561void BooleanLiteral::dump(int indent) const
562{
563 print_indent(indent);
564 printf("BooleanLiteral %s\n", m_value ? "true" : "false");
565}
566
567void NullLiteral::dump(int indent) const
568{
569 print_indent(indent);
570 printf("null\n");
571}
572
573void FunctionNode::dump(int indent, const char* class_name) const
574{
575 StringBuilder parameters_builder;
576 parameters_builder.join(',', parameters());
577
578 print_indent(indent);
579 printf("%s '%s(%s)'\n", class_name, name().characters(), parameters_builder.build().characters());
580 body().dump(indent + 1);
581}
582
583void FunctionDeclaration::dump(int indent) const
584{
585 FunctionNode::dump(indent, class_name());
586}
587
588void FunctionExpression::dump(int indent) const
589{
590 FunctionNode::dump(indent, class_name());
591}
592
593void ReturnStatement::dump(int indent) const
594{
595 ASTNode::dump(indent);
596 if (argument())
597 argument()->dump(indent + 1);
598}
599
600void IfStatement::dump(int indent) const
601{
602 ASTNode::dump(indent);
603
604 print_indent(indent);
605 printf("If\n");
606 predicate().dump(indent + 1);
607 consequent().dump(indent + 1);
608 if (alternate()) {
609 print_indent(indent);
610 printf("Else\n");
611 alternate()->dump(indent + 1);
612 }
613}
614
615void WhileStatement::dump(int indent) const
616{
617 ASTNode::dump(indent);
618
619 print_indent(indent);
620 printf("While\n");
621 test().dump(indent + 1);
622 body().dump(indent + 1);
623}
624
625void DoWhileStatement::dump(int indent) const
626{
627 ASTNode::dump(indent);
628
629 print_indent(indent);
630 printf("DoWhile\n");
631 test().dump(indent + 1);
632 body().dump(indent + 1);
633}
634
635void ForStatement::dump(int indent) const
636{
637 ASTNode::dump(indent);
638
639 print_indent(indent);
640 printf("For\n");
641 if (init())
642 init()->dump(indent + 1);
643 if (test())
644 test()->dump(indent + 1);
645 if (update())
646 update()->dump(indent + 1);
647 body().dump(indent + 1);
648}
649
650Value Identifier::execute(Interpreter& interpreter) const
651{
652 auto variable = interpreter.get_variable(string());
653 if (!variable.has_value())
654 return interpreter.throw_exception<Error>("ReferenceError", String::format("'%s' not known", string().characters()));
655 return variable.value();
656}
657
658void Identifier::dump(int indent) const
659{
660 print_indent(indent);
661 printf("Identifier \"%s\"\n", m_string.characters());
662}
663
664Value AssignmentExpression::execute(Interpreter& interpreter) const
665{
666 auto rhs_result = m_rhs->execute(interpreter);
667 if (interpreter.exception())
668 return {};
669
670 Value lhs_result;
671 switch (m_op) {
672 case AssignmentOp::Assignment:
673 break;
674 case AssignmentOp::AdditionAssignment:
675 lhs_result = m_lhs->execute(interpreter);
676 if (interpreter.exception())
677 return {};
678 rhs_result = add(lhs_result, rhs_result);
679 break;
680 case AssignmentOp::SubtractionAssignment:
681 lhs_result = m_lhs->execute(interpreter);
682 if (interpreter.exception())
683 return {};
684 rhs_result = sub(lhs_result, rhs_result);
685 break;
686 case AssignmentOp::MultiplicationAssignment:
687 lhs_result = m_lhs->execute(interpreter);
688 if (interpreter.exception())
689 return {};
690 rhs_result = mul(lhs_result, rhs_result);
691 break;
692 case AssignmentOp::DivisionAssignment:
693 lhs_result = m_lhs->execute(interpreter);
694 if (interpreter.exception())
695 return {};
696 rhs_result = div(lhs_result, rhs_result);
697 break;
698 }
699 if (interpreter.exception())
700 return {};
701
702 if (m_lhs->is_identifier()) {
703 auto name = static_cast<const Identifier&>(*m_lhs).string();
704 interpreter.set_variable(name, rhs_result);
705 } else if (m_lhs->is_member_expression()) {
706 auto object_value = static_cast<const MemberExpression&>(*m_lhs).object().execute(interpreter);
707 if (interpreter.exception())
708 return {};
709 if (auto* object = object_value.to_object(interpreter.heap())) {
710 auto property_name = static_cast<const MemberExpression&>(*m_lhs).computed_property_name(interpreter);
711 object->put(property_name, rhs_result);
712 }
713 } else {
714 ASSERT_NOT_REACHED();
715 }
716
717 return rhs_result;
718}
719
720Value UpdateExpression::execute(Interpreter& interpreter) const
721{
722 ASSERT(m_argument->is_identifier());
723 auto name = static_cast<const Identifier&>(*m_argument).string();
724
725 auto previous_variable = interpreter.get_variable(name);
726 ASSERT(previous_variable.has_value());
727 auto previous_value = previous_variable.value();
728 ASSERT(previous_value.is_number());
729
730 int op_result = 0;
731 switch (m_op) {
732 case UpdateOp::Increment:
733 op_result = 1;
734 break;
735 case UpdateOp::Decrement:
736 op_result = -1;
737 break;
738 }
739
740 interpreter.set_variable(name, Value(previous_value.as_double() + op_result));
741
742 if (m_prefixed)
743 return JS::Value(previous_value.as_double() + op_result);
744
745 return previous_value;
746}
747
748void AssignmentExpression::dump(int indent) const
749{
750 const char* op_string = nullptr;
751 switch (m_op) {
752 case AssignmentOp::Assignment:
753 op_string = "=";
754 break;
755 case AssignmentOp::AdditionAssignment:
756 op_string = "+=";
757 break;
758 case AssignmentOp::SubtractionAssignment:
759 op_string = "-=";
760 break;
761 case AssignmentOp::MultiplicationAssignment:
762 op_string = "*=";
763 break;
764 case AssignmentOp::DivisionAssignment:
765 op_string = "/=";
766 break;
767 }
768
769 ASTNode::dump(indent);
770 print_indent(indent + 1);
771 printf("%s\n", op_string);
772 m_lhs->dump(indent + 1);
773 m_rhs->dump(indent + 1);
774}
775
776void UpdateExpression::dump(int indent) const
777{
778 const char* op_string = nullptr;
779 switch (m_op) {
780 case UpdateOp::Increment:
781 op_string = "++";
782 break;
783 case UpdateOp::Decrement:
784 op_string = "--";
785 break;
786 }
787
788 ASTNode::dump(indent);
789 print_indent(indent + 1);
790 if (m_prefixed)
791 printf("%s\n", op_string);
792 m_argument->dump(indent + 1);
793 if (!m_prefixed) {
794 print_indent(indent + 1);
795 printf("%s\n", op_string);
796 }
797}
798
799Value VariableDeclaration::execute(Interpreter& interpreter) const
800{
801 for (auto& declarator : m_declarations) {
802 interpreter.declare_variable(declarator.id().string(), m_declaration_kind);
803 if (auto* init = declarator.init()) {
804 auto initalizer_result = init->execute(interpreter);
805 if (interpreter.exception())
806 return {};
807 interpreter.set_variable(declarator.id().string(), initalizer_result, true);
808 }
809 }
810 return js_undefined();
811}
812
813Value VariableDeclarator::execute(Interpreter&) const
814{
815 // NOTE: This node is handled by VariableDeclaration.
816 ASSERT_NOT_REACHED();
817}
818
819void VariableDeclaration::dump(int indent) const
820{
821 const char* declaration_kind_string = nullptr;
822 switch (m_declaration_kind) {
823 case DeclarationKind::Let:
824 declaration_kind_string = "Let";
825 break;
826 case DeclarationKind::Var:
827 declaration_kind_string = "Var";
828 break;
829 case DeclarationKind::Const:
830 declaration_kind_string = "Const";
831 break;
832 }
833
834 ASTNode::dump(indent);
835 print_indent(indent + 1);
836 printf("%s\n", declaration_kind_string);
837
838 for (auto& declarator : m_declarations)
839 declarator.dump(indent + 1);
840}
841
842void VariableDeclarator::dump(int indent) const
843{
844 ASTNode::dump(indent);
845 m_id->dump(indent + 1);
846 if (m_init)
847 m_init->dump(indent + 1);
848}
849
850void ObjectExpression::dump(int indent) const
851{
852 ASTNode::dump(indent);
853 for (auto it : m_properties) {
854 print_indent(indent + 1);
855 printf("%s: ", it.key.characters());
856 it.value->dump(0);
857 }
858}
859
860void ExpressionStatement::dump(int indent) const
861{
862 ASTNode::dump(indent);
863 m_expression->dump(indent + 1);
864}
865
866Value ObjectExpression::execute(Interpreter& interpreter) const
867{
868 auto object = interpreter.heap().allocate<Object>();
869 for (auto it : m_properties) {
870 auto value = it.value->execute(interpreter);
871 if (interpreter.exception())
872 return {};
873 object->put(it.key, value);
874 }
875 return object;
876}
877
878void MemberExpression::dump(int indent) const
879{
880 print_indent(indent);
881 printf("%s (computed=%s)\n", class_name(), is_computed() ? "true" : "false");
882 m_object->dump(indent + 1);
883 m_property->dump(indent + 1);
884}
885
886PropertyName MemberExpression::computed_property_name(Interpreter& interpreter) const
887{
888 if (!is_computed()) {
889 ASSERT(m_property->is_identifier());
890 return PropertyName(static_cast<const Identifier&>(*m_property).string());
891 }
892 auto index = m_property->execute(interpreter);
893 if (interpreter.exception())
894 return {};
895 ASSERT(!index.is_empty());
896 // FIXME: What about non-integer numbers tho.
897 if (index.is_number() && index.to_i32() >= 0)
898 return PropertyName(index.to_i32());
899 return PropertyName(index.to_string());
900}
901
902Value MemberExpression::execute(Interpreter& interpreter) const
903{
904 auto object_value = m_object->execute(interpreter);
905 if (interpreter.exception())
906 return {};
907 auto* object_result = object_value.to_object(interpreter.heap());
908 if (interpreter.exception())
909 return {};
910 auto result = object_result->get(computed_property_name(interpreter));
911 if (result.has_value()) {
912 ASSERT(!result.value().is_empty());
913 }
914 return result.value_or(js_undefined());
915}
916
917Value StringLiteral::execute(Interpreter& interpreter) const
918{
919 return js_string(interpreter, m_value);
920}
921
922Value NumericLiteral::execute(Interpreter&) const
923{
924 return Value(m_value);
925}
926
927Value BooleanLiteral::execute(Interpreter&) const
928{
929 return Value(m_value);
930}
931
932Value NullLiteral::execute(Interpreter&) const
933{
934 return js_null();
935}
936
937void ArrayExpression::dump(int indent) const
938{
939 ASTNode::dump(indent);
940 for (auto& element : m_elements) {
941 element.dump(indent + 1);
942 }
943}
944
945Value ArrayExpression::execute(Interpreter& interpreter) const
946{
947 auto* array = interpreter.heap().allocate<Array>();
948 for (auto& element : m_elements) {
949 auto value = element.execute(interpreter);
950 if (interpreter.exception())
951 return {};
952 array->push(value);
953 }
954 return array;
955}
956
957void TryStatement::dump(int indent) const
958{
959 ASTNode::dump(indent);
960 print_indent(indent);
961 printf("(Block)\n");
962 block().dump(indent + 1);
963
964 if (handler()) {
965 print_indent(indent);
966 printf("(Handler)\n");
967 handler()->dump(indent + 1);
968 }
969
970 if (finalizer()) {
971 print_indent(indent);
972 printf("(Finalizer)\n");
973 finalizer()->dump(indent + 1);
974 }
975}
976
977void CatchClause::dump(int indent) const
978{
979 print_indent(indent);
980 printf("CatchClause");
981 if (!m_parameter.is_null())
982 printf(" (%s)", m_parameter.characters());
983 printf("\n");
984 body().dump(indent + 1);
985}
986
987void ThrowStatement::dump(int indent) const
988{
989 ASTNode::dump(indent);
990 argument().dump(indent + 1);
991}
992
993Value TryStatement::execute(Interpreter& interpreter) const
994{
995 interpreter.run(block(), {}, ScopeType::Try);
996 if (auto* exception = interpreter.exception()) {
997 if (m_handler) {
998 interpreter.clear_exception();
999 ArgumentVector arguments { { m_handler->parameter(), exception->value() } };
1000 interpreter.run(m_handler->body(), move(arguments));
1001 }
1002 }
1003
1004 if (m_finalizer)
1005 m_finalizer->execute(interpreter);
1006
1007 return js_undefined();
1008}
1009
1010Value CatchClause::execute(Interpreter&) const
1011{
1012 // NOTE: CatchClause execution is handled by TryStatement.
1013 ASSERT_NOT_REACHED();
1014 return {};
1015}
1016
1017Value ThrowStatement::execute(Interpreter& interpreter) const
1018{
1019 auto value = m_argument->execute(interpreter);
1020 if (interpreter.exception())
1021 return {};
1022 return interpreter.throw_exception(value);
1023}
1024
1025Value SwitchStatement::execute(Interpreter& interpreter) const
1026{
1027 auto discriminant_result = m_discriminant->execute(interpreter);
1028 if (interpreter.exception())
1029 return {};
1030
1031 bool falling_through = false;
1032
1033 for (auto& switch_case : m_cases) {
1034 if (!falling_through && switch_case.test()) {
1035 auto test_result = switch_case.test()->execute(interpreter);
1036 if (interpreter.exception())
1037 return {};
1038 if (!eq(discriminant_result, test_result).to_boolean())
1039 continue;
1040 }
1041 falling_through = true;
1042
1043 for (auto& statement : switch_case.consequent()) {
1044 statement.execute(interpreter);
1045 if (interpreter.exception())
1046 return {};
1047 if (interpreter.should_unwind()) {
1048 if (interpreter.should_unwind_until(ScopeType::Breakable)) {
1049 interpreter.stop_unwind();
1050 return {};
1051 }
1052 return {};
1053 }
1054 }
1055 }
1056
1057 return js_undefined();
1058}
1059
1060Value SwitchCase::execute(Interpreter& interpreter) const
1061{
1062 (void)interpreter;
1063 return {};
1064}
1065
1066Value BreakStatement::execute(Interpreter& interpreter) const
1067{
1068 interpreter.unwind(ScopeType::Breakable);
1069 return js_undefined();
1070}
1071
1072Value ContinueStatement::execute(Interpreter& interpreter) const
1073{
1074 interpreter.unwind(ScopeType::Continuable);
1075 return js_undefined();
1076}
1077
1078void SwitchStatement::dump(int indent) const
1079{
1080 ASTNode::dump(indent);
1081 m_discriminant->dump(indent + 1);
1082 for (auto& switch_case : m_cases) {
1083 switch_case.dump(indent + 1);
1084 }
1085}
1086
1087void SwitchCase::dump(int indent) const
1088{
1089 ASTNode::dump(indent);
1090 print_indent(indent);
1091 if (m_test) {
1092 printf("(Test)\n");
1093 m_test->dump(indent + 1);
1094 } else {
1095 printf("(Default)\n");
1096 }
1097 print_indent(indent);
1098 printf("(Consequent)\n");
1099 int i = 0;
1100 for (auto& statement : m_consequent) {
1101 print_indent(indent);
1102 printf("[%d]\n", i++);
1103 statement.dump(indent + 1);
1104 }
1105}
1106
1107Value ConditionalExpression::execute(Interpreter& interpreter) const
1108{
1109 auto test_result = m_test->execute(interpreter);
1110 if (interpreter.exception())
1111 return {};
1112 Value result;
1113 if (test_result.to_boolean()) {
1114 result = m_consequent->execute(interpreter);
1115 } else {
1116 result = m_alternate->execute(interpreter);
1117 }
1118 if (interpreter.exception())
1119 return {};
1120 return result;
1121}
1122
1123void ConditionalExpression::dump(int indent) const
1124{
1125 ASTNode::dump(indent);
1126 print_indent(indent);
1127 printf("(Test)\n");
1128 m_test->dump(indent + 1);
1129 print_indent(indent);
1130 printf("(Consequent)\n");
1131 m_test->dump(indent + 1);
1132 print_indent(indent);
1133 printf("(Alternate)\n");
1134 m_test->dump(indent + 1);
1135}
1136
1137void SequenceExpression::dump(int indent) const
1138{
1139 ASTNode::dump(indent);
1140 for (auto& expression : m_expressions)
1141 expression.dump(indent + 1);
1142}
1143
1144Value SequenceExpression::execute(Interpreter& interpreter) const
1145{
1146 Value last_value;
1147 for (auto& expression : m_expressions) {
1148 last_value = expression.execute(interpreter);
1149 if (interpreter.exception())
1150 return {};
1151 }
1152 return last_value;
1153}
1154
1155}