Serenity Operating System
at hosted 364 lines 10 kB view raw
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/FlyString.h> 28#include <AK/String.h> 29#include <LibJS/Heap/Heap.h> 30#include <LibJS/Interpreter.h> 31#include <LibJS/Runtime/Array.h> 32#include <LibJS/Runtime/BooleanObject.h> 33#include <LibJS/Runtime/Error.h> 34#include <LibJS/Runtime/NumberObject.h> 35#include <LibJS/Runtime/Object.h> 36#include <LibJS/Runtime/PrimitiveString.h> 37#include <LibJS/Runtime/StringObject.h> 38#include <LibJS/Runtime/Value.h> 39#include <math.h> 40 41namespace JS { 42 43bool Value::is_array() const 44{ 45 return is_object() && as_object().is_array(); 46} 47 48String Value::to_string() const 49{ 50 if (is_boolean()) 51 return as_bool() ? "true" : "false"; 52 53 if (is_null()) 54 return "null"; 55 56 if (is_undefined()) 57 return "undefined"; 58 59 if (is_number()) { 60 if (is_nan()) 61 return "NaN"; 62 63 if (is_infinity()) 64 return as_double() < 0 ? "-Infinity" : "Infinity"; 65 66 // FIXME: This needs improvement. 67 if ((double)to_i32() == as_double()) 68 return String::number(to_i32()); 69 return String::format("%f", as_double()); 70 } 71 72 if (is_object()) 73 return as_object().to_primitive(Object::PreferredType::String).to_string(); 74 75 if (is_string()) 76 return m_value.as_string->string(); 77 78 ASSERT_NOT_REACHED(); 79} 80 81bool Value::to_boolean() const 82{ 83 switch (m_type) { 84 case Type::Boolean: 85 return m_value.as_bool; 86 case Type::Number: 87 if (is_nan()) { 88 return false; 89 } 90 return !(m_value.as_double == 0 || m_value.as_double == -0); 91 case Type::Null: 92 case Type::Undefined: 93 return false; 94 case Type::String: 95 return !as_string()->string().is_empty(); 96 case Type::Object: 97 return true; 98 default: 99 ASSERT_NOT_REACHED(); 100 } 101} 102 103Object* Value::to_object(Heap& heap) const 104{ 105 if (is_object()) 106 return &const_cast<Object&>(as_object()); 107 108 if (is_string()) 109 return heap.allocate<StringObject>(m_value.as_string); 110 111 if (is_number()) 112 return heap.allocate<NumberObject>(m_value.as_double); 113 114 if (is_boolean()) 115 return heap.allocate<BooleanObject>(m_value.as_bool); 116 117 if (is_null() || is_undefined()) { 118 heap.interpreter().throw_exception<Error>("TypeError", "ToObject on null or undefined."); 119 return nullptr; 120 } 121 122 dbg() << "Dying because I can't to_object() on " << *this; 123 ASSERT_NOT_REACHED(); 124} 125 126Value Value::to_number() const 127{ 128 switch (m_type) { 129 case Type::Empty: 130 ASSERT_NOT_REACHED(); 131 return {}; 132 case Type::Boolean: 133 return Value(m_value.as_bool ? 1 : 0); 134 case Type::Number: 135 return Value(m_value.as_double); 136 case Type::Null: 137 return Value(0); 138 case Type::String: { 139 auto& string = as_string()->string(); 140 if (string.is_empty()) 141 return Value(0); 142 bool ok; 143 //FIXME: Parse in a better way 144 auto parsed_int = string.to_int(ok); 145 if (ok) 146 return Value(parsed_int); 147 148 return js_nan(); 149 } 150 case Type::Undefined: 151 return js_nan(); 152 case Type::Object: 153 if (m_value.as_object->is_array()) { 154 auto& array = *static_cast<Array*>(m_value.as_object); 155 if (array.length() == 0) 156 return Value(0); 157 if (array.length() > 1) 158 return js_nan(); 159 return array.elements()[0].to_number(); 160 } else { 161 return m_value.as_object->to_primitive(Object::PreferredType::Number).to_number(); 162 } 163 } 164 165 ASSERT_NOT_REACHED(); 166} 167 168i32 Value::to_i32() const 169{ 170 return static_cast<i32>(to_number().as_double()); 171} 172 173double Value::to_double() const 174{ 175 return to_number().as_double(); 176} 177 178Value greater_than(Value lhs, Value rhs) 179{ 180 return Value(lhs.to_number().as_double() > rhs.to_number().as_double()); 181} 182 183Value greater_than_equals(Value lhs, Value rhs) 184{ 185 return Value(lhs.to_number().as_double() >= rhs.to_number().as_double()); 186} 187 188Value less_than(Value lhs, Value rhs) 189{ 190 return Value(lhs.to_number().as_double() < rhs.to_number().as_double()); 191} 192 193Value less_than_equals(Value lhs, Value rhs) 194{ 195 return Value(lhs.to_number().as_double() <= rhs.to_number().as_double()); 196} 197 198Value bitwise_and(Value lhs, Value rhs) 199{ 200 return Value((i32)lhs.to_number().as_double() & (i32)rhs.to_number().as_double()); 201} 202 203Value bitwise_or(Value lhs, Value rhs) 204{ 205 bool lhs_invalid = lhs.is_undefined() || lhs.is_null() || lhs.is_nan() || lhs.is_infinity(); 206 bool rhs_invalid = rhs.is_undefined() || rhs.is_null() || rhs.is_nan() || rhs.is_infinity(); 207 208 if (lhs_invalid && rhs_invalid) 209 return Value(0); 210 211 if (lhs_invalid || rhs_invalid) 212 return lhs_invalid ? rhs.to_number() : lhs.to_number(); 213 214 if (!rhs.is_number() && !lhs.is_number()) 215 return Value(0); 216 217 return Value((i32)lhs.to_number().as_double() | (i32)rhs.to_number().as_double()); 218} 219 220Value bitwise_xor(Value lhs, Value rhs) 221{ 222 return Value((i32)lhs.to_number().as_double() ^ (i32)rhs.to_number().as_double()); 223} 224 225Value bitwise_not(Value lhs) 226{ 227 return Value(~(i32)lhs.to_number().as_double()); 228} 229 230Value unary_plus(Value lhs) 231{ 232 return lhs.to_number(); 233} 234 235Value unary_minus(Value lhs) 236{ 237 if (lhs.to_number().is_nan()) 238 return js_nan(); 239 return Value(-lhs.to_number().as_double()); 240} 241 242Value left_shift(Value lhs, Value rhs) 243{ 244 return Value((i32)lhs.to_number().as_double() << (i32)rhs.to_number().as_double()); 245} 246 247Value right_shift(Value lhs, Value rhs) 248{ 249 return Value((i32)lhs.to_number().as_double() >> (i32)rhs.to_number().as_double()); 250} 251 252Value add(Value lhs, Value rhs) 253{ 254 if (lhs.is_string() || rhs.is_string()) 255 return js_string((lhs.is_string() ? lhs : rhs).as_string()->heap(), String::format("%s%s", lhs.to_string().characters(), rhs.to_string().characters())); 256 257 return Value(lhs.to_number().as_double() + rhs.to_number().as_double()); 258} 259 260Value sub(Value lhs, Value rhs) 261{ 262 return Value(lhs.to_number().as_double() - rhs.to_number().as_double()); 263} 264 265Value mul(Value lhs, Value rhs) 266{ 267 return Value(lhs.to_number().as_double() * rhs.to_number().as_double()); 268} 269 270Value div(Value lhs, Value rhs) 271{ 272 return Value(lhs.to_number().as_double() / rhs.to_number().as_double()); 273} 274 275Value mod(Value lhs, Value rhs) 276{ 277 if (lhs.to_number().is_nan() || rhs.to_number().is_nan()) 278 return js_nan(); 279 280 double index = lhs.to_number().as_double(); 281 double period = rhs.to_number().as_double(); 282 double trunc = (double)(i32) (index / period); 283 284 return Value(index - trunc * period); 285} 286 287Value exp(Value lhs, Value rhs) 288{ 289 return Value(pow(lhs.to_number().as_double(), rhs.to_number().as_double())); 290} 291 292Value typed_eq(Value lhs, Value rhs) 293{ 294 if (rhs.type() != lhs.type()) 295 return Value(false); 296 297 switch (lhs.type()) { 298 case Value::Type::Empty: 299 ASSERT_NOT_REACHED(); 300 return {}; 301 case Value::Type::Undefined: 302 return Value(true); 303 case Value::Type::Null: 304 return Value(true); 305 case Value::Type::Number: 306 return Value(lhs.as_double() == rhs.as_double()); 307 case Value::Type::String: 308 return Value(lhs.as_string()->string() == rhs.as_string()->string()); 309 case Value::Type::Boolean: 310 return Value(lhs.as_bool() == rhs.as_bool()); 311 case Value::Type::Object: 312 return Value(&lhs.as_object() == &rhs.as_object()); 313 } 314 315 ASSERT_NOT_REACHED(); 316} 317 318Value eq(Value lhs, Value rhs) 319{ 320 if (lhs.type() == rhs.type()) 321 return typed_eq(lhs, rhs); 322 323 if ((lhs.is_undefined() || lhs.is_null()) && (rhs.is_undefined() || rhs.is_null())) 324 return Value(true); 325 326 if (lhs.is_object() && rhs.is_boolean()) 327 return eq(lhs.as_object().to_primitive(), rhs.to_number()); 328 329 if (lhs.is_boolean() && rhs.is_object()) 330 return eq(lhs.to_number(), rhs.as_object().to_primitive()); 331 332 if (lhs.is_object()) 333 return eq(lhs.as_object().to_primitive(), rhs); 334 335 if (rhs.is_object()) 336 return eq(lhs, rhs.as_object().to_primitive()); 337 338 if (lhs.is_number() || rhs.is_number()) 339 return Value(lhs.to_number().as_double() == rhs.to_number().as_double()); 340 341 if ((lhs.is_string() && rhs.is_boolean()) || (lhs.is_string() && rhs.is_boolean())) 342 return Value(lhs.to_number().as_double() == rhs.to_number().as_double()); 343 344 return Value(false); 345} 346 347Value instance_of(Value lhs, Value rhs) 348{ 349 if (!lhs.is_object() || !rhs.is_object()) 350 return Value(false); 351 352 auto constructor_prototype_property = rhs.as_object().get("prototype"); 353 if (!constructor_prototype_property.has_value() || !constructor_prototype_property.value().is_object()) 354 return Value(false); 355 356 return Value(lhs.as_object().has_prototype(&constructor_prototype_property.value().as_object())); 357} 358 359const LogStream& operator<<(const LogStream& stream, const Value& value) 360{ 361 return stream << value.to_string(); 362} 363 364}