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/Assertions.h>
30#include <AK/Forward.h>
31#include <AK/LogStream.h>
32#include <LibJS/Forward.h>
33
34namespace JS {
35
36class Value {
37public:
38 enum class Type {
39 Empty,
40 Undefined,
41 Null,
42 Number,
43 String,
44 Object,
45 Boolean,
46 };
47
48 bool is_empty() const { return m_type == Type::Empty; }
49 bool is_undefined() const { return m_type == Type::Undefined; }
50 bool is_null() const { return m_type == Type::Null; }
51 bool is_number() const { return m_type == Type::Number; }
52 bool is_string() const { return m_type == Type::String; }
53 bool is_object() const { return m_type == Type::Object; }
54 bool is_boolean() const { return m_type == Type::Boolean; }
55 bool is_cell() const { return is_string() || is_object(); }
56 bool is_array() const;
57
58 bool is_nan() const { return is_number() && __builtin_isnan(as_double()); }
59 bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); }
60
61 Value()
62 : m_type(Type::Empty)
63 {
64 }
65
66 explicit Value(bool value)
67 : m_type(Type::Boolean)
68 {
69 m_value.as_bool = value;
70 }
71
72 explicit Value(double value)
73 : m_type(Type::Number)
74 {
75 m_value.as_double = value;
76 }
77
78 explicit Value(i32 value)
79 : m_type(Type::Number)
80 {
81 m_value.as_double = value;
82 }
83
84 Value(Object* object)
85 : m_type(object ? Type::Object : Type::Null)
86 {
87 m_value.as_object = object;
88 }
89
90 Value(PrimitiveString* string)
91 : m_type(Type::String)
92 {
93 m_value.as_string = string;
94 }
95
96 explicit Value(Type type)
97 : m_type(type)
98 {
99 }
100
101 Type type() const { return m_type; }
102
103 double as_double() const
104 {
105 ASSERT(type() == Type::Number);
106 return m_value.as_double;
107 }
108
109 bool as_bool() const
110 {
111 ASSERT(type() == Type::Boolean);
112 return m_value.as_bool;
113 }
114
115 Object& as_object()
116 {
117 ASSERT(type() == Type::Object);
118 return *m_value.as_object;
119 }
120
121 const Object& as_object() const
122 {
123 ASSERT(type() == Type::Object);
124 return *m_value.as_object;
125 }
126
127 PrimitiveString* as_string()
128 {
129 ASSERT(is_string());
130 return m_value.as_string;
131 }
132
133 const PrimitiveString* as_string() const
134 {
135 ASSERT(is_string());
136 return m_value.as_string;
137 }
138
139 Cell* as_cell()
140 {
141 ASSERT(is_cell());
142 return m_value.as_cell;
143 }
144
145 String to_string() const;
146 bool to_boolean() const;
147 Value to_number() const;
148 i32 to_i32() const;
149 double to_double() const;
150
151 Object* to_object(Heap&) const;
152
153private:
154 Type m_type { Type::Undefined };
155
156 union {
157 bool as_bool;
158 double as_double;
159 PrimitiveString* as_string;
160 Object* as_object;
161 Cell* as_cell;
162 } m_value;
163};
164
165inline Value js_undefined()
166{
167 return Value(Value::Type::Undefined);
168}
169
170inline Value js_null()
171{
172 return Value(Value::Type::Null);
173}
174
175inline Value js_nan()
176{
177 return Value(__builtin_nan(""));
178}
179
180inline Value js_infinity()
181{
182 return Value(__builtin_huge_val());
183}
184
185Value greater_than(Value lhs, Value rhs);
186Value greater_than_equals(Value lhs, Value rhs);
187Value less_than(Value lhs, Value rhs);
188Value less_than_equals(Value lhs, Value rhs);
189Value bitwise_and(Value lhs, Value rhs);
190Value bitwise_or(Value lhs, Value rhs);
191Value bitwise_xor(Value lhs, Value rhs);
192Value bitwise_not(Value);
193Value unary_plus(Value);
194Value unary_minus(Value);
195Value left_shift(Value lhs, Value rhs);
196Value right_shift(Value lhs, Value rhs);
197Value add(Value lhs, Value rhs);
198Value sub(Value lhs, Value rhs);
199Value mul(Value lhs, Value rhs);
200Value div(Value lhs, Value rhs);
201Value mod(Value lhs, Value rhs);
202Value exp(Value lhs, Value rhs);
203Value eq(Value lhs, Value rhs);
204Value typed_eq(Value lhs, Value rhs);
205Value instance_of(Value lhs, Value rhs);
206
207const LogStream& operator<<(const LogStream&, const Value&);
208
209}