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#pragma once
28
29#include <AK/FlyString.h>
30#include <AK/HashMap.h>
31#include <AK/String.h>
32#include <AK/Vector.h>
33#include <LibJS/Forward.h>
34#include <LibJS/Heap/Heap.h>
35#include <LibJS/Runtime/Exception.h>
36#include <LibJS/Runtime/Value.h>
37
38namespace JS {
39
40enum class ScopeType {
41 None,
42 Function,
43 Block,
44 Try,
45 Breakable,
46 Continuable,
47};
48
49struct Variable {
50 Value value;
51 DeclarationKind declaration_kind;
52};
53
54struct ScopeFrame {
55 ScopeType type;
56 NonnullRefPtr<ScopeNode> scope_node;
57 HashMap<FlyString, Variable> variables;
58};
59
60struct CallFrame {
61 Value this_value;
62 Vector<Value> arguments;
63};
64
65struct Argument {
66 FlyString name;
67 Value value;
68};
69
70typedef Vector<Argument, 8> ArgumentVector;
71
72class Interpreter {
73public:
74 template<typename GlobalObjectType, typename... Args>
75 static NonnullOwnPtr<Interpreter> create(Args&&... args)
76 {
77 auto interpreter = adopt_own(*new Interpreter);
78 interpreter->m_global_object = interpreter->heap().allocate<GlobalObjectType>(forward<Args>(args)...);
79 return interpreter;
80 }
81
82 ~Interpreter();
83
84 Value run(const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
85
86 GlobalObject& global_object();
87 const GlobalObject& global_object() const;
88
89 Heap& heap() { return m_heap; }
90
91 void unwind(ScopeType type) { m_unwind_until = type; }
92 void stop_unwind() { m_unwind_until = ScopeType::None; }
93 bool should_unwind_until(ScopeType type) const { return m_unwind_until == type; }
94 bool should_unwind() const { return m_unwind_until != ScopeType::None; }
95
96 Optional<Value> get_variable(const FlyString& name);
97 void set_variable(const FlyString& name, Value, bool first_assignment = false);
98 void declare_variable(const FlyString& name, DeclarationKind);
99
100 void gather_roots(Badge<Heap>, HashTable<Cell*>&);
101
102 void enter_scope(const ScopeNode&, ArgumentVector, ScopeType);
103 void exit_scope(const ScopeNode&);
104
105 Value call(Function*, Value this_value = {}, const Vector<Value>& arguments = {});
106
107 CallFrame& push_call_frame()
108 {
109 m_call_stack.append({ js_undefined(), {} });
110 return m_call_stack.last();
111 }
112 void pop_call_frame() { m_call_stack.take_last(); }
113 const CallFrame& call_frame() { return m_call_stack.last(); }
114
115 size_t argument_count() const
116 {
117 if (m_call_stack.is_empty())
118 return 0;
119 return m_call_stack.last().arguments.size();
120 }
121
122 Value argument(size_t index) const
123 {
124 if (m_call_stack.is_empty())
125 return {};
126 auto& arguments = m_call_stack.last().arguments;
127 return index < arguments.size() ? arguments[index] : js_undefined();
128 }
129
130 Value this_value() const
131 {
132 if (m_call_stack.is_empty())
133 return m_global_object;
134 return m_call_stack.last().this_value;
135 }
136
137 Shape* empty_object_shape() { return m_empty_object_shape; }
138
139 Object* string_prototype() { return m_string_prototype; }
140 Object* object_prototype() { return m_object_prototype; }
141 Object* array_prototype() { return m_array_prototype; }
142 Object* error_prototype() { return m_error_prototype; }
143 Object* date_prototype() { return m_date_prototype; }
144 Object* function_prototype() { return m_function_prototype; }
145 Object* number_prototype() { return m_number_prototype; }
146 Object* boolean_prototype() { return m_boolean_prototype; }
147
148 Exception* exception() { return m_exception; }
149 void clear_exception() { m_exception = nullptr; }
150
151 template<typename T, typename... Args>
152 Value throw_exception(Args&&... args)
153 {
154 return throw_exception(heap().allocate<T>(forward<Args>(args)...));
155 }
156
157 Value throw_exception(Exception*);
158 Value throw_exception(Value value)
159 {
160 return throw_exception(heap().allocate<Exception>(value));
161 }
162
163 Value last_value() const { return m_last_value; }
164
165private:
166 Interpreter();
167
168 Heap m_heap;
169
170 Value m_last_value;
171
172 Vector<ScopeFrame> m_scope_stack;
173 Vector<CallFrame> m_call_stack;
174
175 Shape* m_empty_object_shape { nullptr };
176
177 Object* m_global_object { nullptr };
178 Object* m_string_prototype { nullptr };
179 Object* m_object_prototype { nullptr };
180 Object* m_array_prototype { nullptr };
181 Object* m_error_prototype { nullptr };
182 Object* m_date_prototype { nullptr };
183 Object* m_function_prototype { nullptr };
184 Object* m_number_prototype { nullptr };
185 Object* m_boolean_prototype { nullptr };
186
187 Exception* m_exception { nullptr };
188
189 ScopeType m_unwind_until { ScopeType::None };
190};
191
192}