@ugo-studio/jspp 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/analysis/scope.js +38 -15
- package/dist/analysis/typeAnalyzer.js +257 -23
- package/dist/ast/types.js +6 -0
- package/dist/cli.js +3 -4
- package/dist/core/codegen/class-handlers.js +127 -0
- package/dist/core/codegen/control-flow-handlers.js +464 -0
- package/dist/core/codegen/declaration-handlers.js +31 -14
- package/dist/core/codegen/expression-handlers.js +432 -116
- package/dist/core/codegen/function-handlers.js +110 -13
- package/dist/core/codegen/helpers.js +76 -8
- package/dist/core/codegen/index.js +18 -5
- package/dist/core/codegen/literal-handlers.js +3 -0
- package/dist/core/codegen/statement-handlers.js +152 -186
- package/dist/core/codegen/visitor.js +35 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +658 -734
- package/src/prelude/any_value_access.hpp +103 -0
- package/src/prelude/any_value_defines.hpp +151 -0
- package/src/prelude/any_value_helpers.hpp +246 -0
- package/src/prelude/exception.hpp +31 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +35 -12
- package/src/prelude/library/console.hpp +20 -20
- package/src/prelude/library/error.hpp +111 -0
- package/src/prelude/library/global.hpp +15 -4
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/promise.hpp +121 -0
- package/src/prelude/library/symbol.hpp +60 -4
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +33 -6
- package/src/prelude/utils/access.hpp +174 -0
- package/src/prelude/utils/log_any_value/array.hpp +245 -0
- package/src/prelude/utils/log_any_value/config.hpp +32 -0
- package/src/prelude/utils/log_any_value/function.hpp +37 -0
- package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
- package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
- package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
- package/src/prelude/utils/log_any_value/object.hpp +119 -0
- package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
- package/src/prelude/{operators.hpp → utils/operators.hpp} +31 -12
- package/src/prelude/utils/well_known_symbols.hpp +13 -0
- package/src/prelude/values/array.hpp +5 -2
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +76 -19
- package/src/prelude/values/{operators → helpers}/array.hpp +30 -14
- package/src/prelude/values/helpers/function.hpp +125 -0
- package/src/prelude/values/helpers/iterator.hpp +107 -0
- package/src/prelude/values/helpers/object.hpp +64 -0
- package/src/prelude/values/helpers/promise.hpp +181 -0
- package/src/prelude/values/helpers/string.hpp +50 -0
- package/src/prelude/values/helpers/symbol.hpp +23 -0
- package/src/prelude/values/iterator.hpp +96 -0
- package/src/prelude/values/object.hpp +8 -3
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +23 -16
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +58 -0
- package/src/prelude/values/prototypes/object.hpp +26 -0
- package/src/prelude/values/prototypes/promise.hpp +124 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +41 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/access.hpp +0 -86
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -403
- package/src/prelude/values/operators/function.hpp +0 -34
- package/src/prelude/values/operators/object.hpp +0 -34
- package/src/prelude/well_known_symbols.hpp +0 -10
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
|
|
6
|
+
jspp::AnyValue jspp::AnyValue::get_own_property(const std::string &key) const
|
|
7
|
+
{
|
|
8
|
+
return get_property_with_receiver(key, *this);
|
|
9
|
+
}
|
|
10
|
+
jspp::AnyValue jspp::AnyValue::get_own_property(uint32_t idx) const noexcept
|
|
11
|
+
{
|
|
12
|
+
switch (storage.type)
|
|
13
|
+
{
|
|
14
|
+
case JsType::Array:
|
|
15
|
+
return storage.array->get_property(idx);
|
|
16
|
+
case JsType::String:
|
|
17
|
+
return storage.str->get_property(idx);
|
|
18
|
+
default:
|
|
19
|
+
return get_own_property(std::to_string(idx));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
jspp::AnyValue jspp::AnyValue::get_own_property(const AnyValue &key) const noexcept
|
|
23
|
+
{
|
|
24
|
+
if (key.storage.type == JsType::Number && storage.type == JsType::Array)
|
|
25
|
+
return storage.array->get_property(key.storage.number);
|
|
26
|
+
if (key.storage.type == JsType::Number && storage.type == JsType::String)
|
|
27
|
+
return storage.str->get_property(key.storage.number);
|
|
28
|
+
|
|
29
|
+
// If the key is a Symbol, use its internal key string
|
|
30
|
+
if (key.storage.type == JsType::Symbol)
|
|
31
|
+
return get_own_property(key.storage.symbol->key);
|
|
32
|
+
|
|
33
|
+
return get_own_property(key.to_std_string());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
jspp::AnyValue jspp::AnyValue::get_property_with_receiver(const std::string &key, const AnyValue &receiver) const
|
|
37
|
+
{
|
|
38
|
+
switch (storage.type)
|
|
39
|
+
{
|
|
40
|
+
case JsType::Object:
|
|
41
|
+
return storage.object->get_property(key, receiver);
|
|
42
|
+
case JsType::Array:
|
|
43
|
+
return storage.array->get_property(key, receiver);
|
|
44
|
+
case JsType::Function:
|
|
45
|
+
return storage.function->get_property(key, receiver);
|
|
46
|
+
case JsType::Promise:
|
|
47
|
+
return storage.promise->get_property(key, receiver);
|
|
48
|
+
case JsType::Iterator:
|
|
49
|
+
return storage.iterator->get_property(key, receiver);
|
|
50
|
+
case JsType::Symbol:
|
|
51
|
+
return storage.symbol->get_property(key, receiver);
|
|
52
|
+
case JsType::String:
|
|
53
|
+
return storage.str->get_property(key, receiver);
|
|
54
|
+
case JsType::Undefined:
|
|
55
|
+
throw Exception::make_exception("Cannot read properties of undefined (reading '" + key + "')", "TypeError");
|
|
56
|
+
case JsType::Null:
|
|
57
|
+
throw Exception::make_exception("Cannot read properties of null (reading '" + key + "')", "TypeError");
|
|
58
|
+
default:
|
|
59
|
+
return AnyValue::make_undefined();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
jspp::AnyValue jspp::AnyValue::set_own_property(const std::string &key, const AnyValue &value) const
|
|
64
|
+
{
|
|
65
|
+
switch (storage.type)
|
|
66
|
+
{
|
|
67
|
+
case JsType::Object:
|
|
68
|
+
return storage.object->set_property(key, value, *this);
|
|
69
|
+
case JsType::Array:
|
|
70
|
+
return storage.array->set_property(key, value, *this);
|
|
71
|
+
case JsType::Function:
|
|
72
|
+
return storage.function->set_property(key, value, *this);
|
|
73
|
+
case JsType::Promise:
|
|
74
|
+
return storage.promise->set_property(key, value, *this);
|
|
75
|
+
case JsType::Undefined:
|
|
76
|
+
throw Exception::make_exception("Cannot set properties of undefined (setting '" + key + "')", "TypeError");
|
|
77
|
+
case JsType::Null:
|
|
78
|
+
throw Exception::make_exception("Cannot set properties of null (setting '" + key + "')", "TypeError");
|
|
79
|
+
default:
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
jspp::AnyValue jspp::AnyValue::set_own_property(uint32_t idx, const AnyValue &value) const
|
|
84
|
+
{
|
|
85
|
+
if (storage.type == JsType::Array)
|
|
86
|
+
{
|
|
87
|
+
return storage.array->set_property(idx, value);
|
|
88
|
+
}
|
|
89
|
+
return set_own_property(std::to_string(idx), value);
|
|
90
|
+
}
|
|
91
|
+
jspp::AnyValue jspp::AnyValue::set_own_property(const AnyValue &key, const AnyValue &value) const
|
|
92
|
+
{
|
|
93
|
+
if (key.storage.type == JsType::Number && storage.type == JsType::Array)
|
|
94
|
+
{
|
|
95
|
+
return storage.array->set_property(key.storage.number, value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// If the key is a Symbol, use its internal key string
|
|
99
|
+
if (key.storage.type == JsType::Symbol)
|
|
100
|
+
return set_own_property(key.storage.symbol->key, value);
|
|
101
|
+
|
|
102
|
+
return set_own_property(key.to_std_string(), value);
|
|
103
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
#include "values/object.hpp"
|
|
6
|
+
#include "values/function.hpp"
|
|
7
|
+
|
|
8
|
+
namespace jspp
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
inline void AnyValue::define_data_property(const std::string &key, const AnyValue &value)
|
|
12
|
+
{
|
|
13
|
+
if (is_object())
|
|
14
|
+
{
|
|
15
|
+
storage.object->props[key] = value;
|
|
16
|
+
}
|
|
17
|
+
else if (is_function())
|
|
18
|
+
{
|
|
19
|
+
storage.function->props[key] = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
inline void AnyValue::define_data_property(const AnyValue &key, const AnyValue &value)
|
|
24
|
+
{
|
|
25
|
+
if (key.is_symbol())
|
|
26
|
+
define_data_property(key.as_symbol()->key, value);
|
|
27
|
+
else
|
|
28
|
+
define_data_property(key.to_std_string(), value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
inline void AnyValue::define_data_property(const std::string &key, const AnyValue &value, bool writable, bool enumerable, bool configurable)
|
|
32
|
+
{
|
|
33
|
+
define_data_property(key, AnyValue::make_data_descriptor(value, writable, enumerable, configurable));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
inline void AnyValue::define_getter(const std::string &key, const AnyValue &getter)
|
|
37
|
+
{
|
|
38
|
+
if (is_object())
|
|
39
|
+
{
|
|
40
|
+
auto &props = storage.object->props;
|
|
41
|
+
auto it = props.find(key);
|
|
42
|
+
if (it != props.end() && it->second.is_accessor_descriptor())
|
|
43
|
+
{
|
|
44
|
+
auto desc = it->second.as_accessor_descriptor();
|
|
45
|
+
desc->get = [getter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
46
|
+
{
|
|
47
|
+
return getter.as_function()->call(thisVal, args);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
{
|
|
52
|
+
auto getFunc = [getter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
53
|
+
{
|
|
54
|
+
return getter.as_function()->call(thisVal, args);
|
|
55
|
+
};
|
|
56
|
+
props[key] = AnyValue::make_accessor_descriptor(getFunc, std::nullopt, true, true);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (is_function())
|
|
60
|
+
{
|
|
61
|
+
auto &props = storage.function->props;
|
|
62
|
+
auto it = props.find(key);
|
|
63
|
+
if (it != props.end() && it->second.is_accessor_descriptor())
|
|
64
|
+
{
|
|
65
|
+
auto desc = it->second.as_accessor_descriptor();
|
|
66
|
+
desc->get = [getter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
67
|
+
{
|
|
68
|
+
return getter.as_function()->call(thisVal, args);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
{
|
|
73
|
+
auto getFunc = [getter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
74
|
+
{
|
|
75
|
+
return getter.as_function()->call(thisVal, args);
|
|
76
|
+
};
|
|
77
|
+
props[key] = AnyValue::make_accessor_descriptor(getFunc, std::nullopt, true, true);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
inline void AnyValue::define_getter(const AnyValue &key, const AnyValue &getter)
|
|
83
|
+
{
|
|
84
|
+
if (key.is_symbol())
|
|
85
|
+
define_getter(key.as_symbol()->key, getter);
|
|
86
|
+
else
|
|
87
|
+
define_getter(key.to_std_string(), getter);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
inline void AnyValue::define_setter(const std::string &key, const AnyValue &setter)
|
|
91
|
+
{
|
|
92
|
+
if (is_object())
|
|
93
|
+
{
|
|
94
|
+
auto &props = storage.object->props;
|
|
95
|
+
auto it = props.find(key);
|
|
96
|
+
if (it != props.end() && it->second.is_accessor_descriptor())
|
|
97
|
+
{
|
|
98
|
+
auto desc = it->second.as_accessor_descriptor();
|
|
99
|
+
desc->set = [setter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
100
|
+
{
|
|
101
|
+
if (args.empty())
|
|
102
|
+
return AnyValue::make_undefined();
|
|
103
|
+
return setter.as_function()->call(thisVal, args);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
auto setFunc = [setter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
109
|
+
{
|
|
110
|
+
if (args.empty())
|
|
111
|
+
return AnyValue::make_undefined();
|
|
112
|
+
return setter.as_function()->call(thisVal, args);
|
|
113
|
+
};
|
|
114
|
+
props[key] = AnyValue::make_accessor_descriptor(std::nullopt, setFunc, true, true);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (is_function())
|
|
118
|
+
{
|
|
119
|
+
auto &props = storage.function->props;
|
|
120
|
+
auto it = props.find(key);
|
|
121
|
+
if (it != props.end() && it->second.is_accessor_descriptor())
|
|
122
|
+
{
|
|
123
|
+
auto desc = it->second.as_accessor_descriptor();
|
|
124
|
+
desc->set = [setter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
125
|
+
{
|
|
126
|
+
if (args.empty())
|
|
127
|
+
return AnyValue::make_undefined();
|
|
128
|
+
return setter.as_function()->call(thisVal, args);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
else
|
|
132
|
+
{
|
|
133
|
+
auto setFunc = [setter](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
|
|
134
|
+
{
|
|
135
|
+
if (args.empty())
|
|
136
|
+
return AnyValue::make_undefined();
|
|
137
|
+
return setter.as_function()->call(thisVal, args);
|
|
138
|
+
};
|
|
139
|
+
props[key] = AnyValue::make_accessor_descriptor(std::nullopt, setFunc, true, true);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
inline void AnyValue::define_setter(const AnyValue &key, const AnyValue &setter)
|
|
145
|
+
{
|
|
146
|
+
if (key.is_symbol())
|
|
147
|
+
define_setter(key.as_symbol()->key, setter);
|
|
148
|
+
else
|
|
149
|
+
define_setter(key.to_std_string(), setter);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
#include "values/string.hpp"
|
|
6
|
+
|
|
7
|
+
namespace jspp
|
|
8
|
+
{
|
|
9
|
+
const bool AnyValue::is_truthy() const noexcept
|
|
10
|
+
{
|
|
11
|
+
switch (storage.type)
|
|
12
|
+
{
|
|
13
|
+
case JsType::Boolean:
|
|
14
|
+
return storage.boolean;
|
|
15
|
+
case JsType::Number:
|
|
16
|
+
return storage.number != 0.0;
|
|
17
|
+
case JsType::String:
|
|
18
|
+
return !storage.str->value.empty();
|
|
19
|
+
case JsType::Undefined:
|
|
20
|
+
return false;
|
|
21
|
+
case JsType::Null:
|
|
22
|
+
return false;
|
|
23
|
+
case JsType::Uninitialized:
|
|
24
|
+
return false;
|
|
25
|
+
default:
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const bool AnyValue::is_strictly_equal_to_primitive(const AnyValue &other) const noexcept
|
|
31
|
+
{
|
|
32
|
+
if (storage.type == other.storage.type)
|
|
33
|
+
{
|
|
34
|
+
switch (storage.type)
|
|
35
|
+
{
|
|
36
|
+
case JsType::Boolean:
|
|
37
|
+
return storage.boolean == other.storage.boolean;
|
|
38
|
+
case JsType::Number:
|
|
39
|
+
return storage.number == other.storage.number;
|
|
40
|
+
case JsType::String:
|
|
41
|
+
return (storage.str->value == other.storage.str->value);
|
|
42
|
+
case JsType::Array:
|
|
43
|
+
return (storage.array == other.storage.array);
|
|
44
|
+
case JsType::Object:
|
|
45
|
+
return (storage.object == other.storage.object);
|
|
46
|
+
case JsType::Function:
|
|
47
|
+
return (storage.function == other.storage.function);
|
|
48
|
+
case JsType::Iterator:
|
|
49
|
+
return (storage.iterator == other.storage.iterator);
|
|
50
|
+
case JsType::Promise:
|
|
51
|
+
return (storage.promise == other.storage.promise);
|
|
52
|
+
case JsType::Symbol:
|
|
53
|
+
// Symbols are unique by reference/pointer identity
|
|
54
|
+
return (storage.symbol == other.storage.symbol);
|
|
55
|
+
case JsType::DataDescriptor:
|
|
56
|
+
return storage.data_desc == other.storage.data_desc;
|
|
57
|
+
case JsType::AccessorDescriptor:
|
|
58
|
+
return storage.accessor_desc == other.storage.accessor_desc;
|
|
59
|
+
default:
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const bool AnyValue::is_equal_to_primitive(const AnyValue &other) const noexcept
|
|
66
|
+
{
|
|
67
|
+
// Implements JavaScript's Abstract Equality Comparison Algorithm (==)
|
|
68
|
+
// Step 1: If types are the same, use strict equality (===)
|
|
69
|
+
if (storage.type == other.storage.type)
|
|
70
|
+
{
|
|
71
|
+
return is_strictly_equal_to_primitive(other);
|
|
72
|
+
}
|
|
73
|
+
// Steps 2 & 3: null == undefined
|
|
74
|
+
if ((is_null() && other.is_undefined()) || (is_undefined() && other.is_null()))
|
|
75
|
+
{
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
// Step 4 & 5: number == string
|
|
79
|
+
if (is_number() && other.is_string())
|
|
80
|
+
{
|
|
81
|
+
double num_this = this->as_double();
|
|
82
|
+
double num_other;
|
|
83
|
+
try
|
|
84
|
+
{
|
|
85
|
+
const std::string &s = other.as_string()->value;
|
|
86
|
+
// JS considers empty string or whitespace-only string to be 0
|
|
87
|
+
if (s.empty() || std::all_of(s.begin(), s.end(), [](unsigned char c)
|
|
88
|
+
{ return std::isspace(c); }))
|
|
89
|
+
{
|
|
90
|
+
num_other = 0.0;
|
|
91
|
+
}
|
|
92
|
+
else
|
|
93
|
+
{
|
|
94
|
+
size_t pos;
|
|
95
|
+
num_other = std::stod(s, &pos);
|
|
96
|
+
// Check if the entire string was consumed, allowing for trailing whitespace
|
|
97
|
+
while (pos < s.length() && std::isspace(static_cast<unsigned char>(s[pos])))
|
|
98
|
+
{
|
|
99
|
+
pos++;
|
|
100
|
+
}
|
|
101
|
+
if (pos != s.length())
|
|
102
|
+
{
|
|
103
|
+
num_other = std::numeric_limits<double>::quiet_NaN();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (...)
|
|
108
|
+
{
|
|
109
|
+
num_other = std::numeric_limits<double>::quiet_NaN();
|
|
110
|
+
}
|
|
111
|
+
return num_this == num_other;
|
|
112
|
+
}
|
|
113
|
+
if (is_string() && other.is_number())
|
|
114
|
+
{
|
|
115
|
+
// Delegate to the other operand to avoid code duplication
|
|
116
|
+
return other.is_equal_to_primitive(*this);
|
|
117
|
+
}
|
|
118
|
+
// Step 6 & 7: boolean == any
|
|
119
|
+
if (is_boolean())
|
|
120
|
+
{
|
|
121
|
+
// Convert boolean to number and re-compare
|
|
122
|
+
return AnyValue::make_number(as_boolean() ? 1.0 : 0.0).is_equal_to_primitive(other);
|
|
123
|
+
}
|
|
124
|
+
if (other.is_boolean())
|
|
125
|
+
{
|
|
126
|
+
// Convert boolean to number and re-compare
|
|
127
|
+
return is_equal_to_primitive(AnyValue::make_number(other.as_boolean() ? 1.0 : 0.0));
|
|
128
|
+
}
|
|
129
|
+
// Step 8 & 9: object == (string or number or symbol)
|
|
130
|
+
// Simplified: Objects convert to primitives.
|
|
131
|
+
if ((is_object() || is_array() || is_function() || is_promise() || is_iterator()) && (other.is_string() || other.is_number() || other.is_symbol()))
|
|
132
|
+
{
|
|
133
|
+
// Convert object to primitive (string) and re-compare.
|
|
134
|
+
// This is a simplification of JS's ToPrimitive.
|
|
135
|
+
return AnyValue::make_string(to_std_string()).is_equal_to_primitive(other);
|
|
136
|
+
}
|
|
137
|
+
if ((other.is_object() || other.is_array() || other.is_function() || other.is_promise() || other.is_iterator()) && (is_string() || is_number() || is_symbol()))
|
|
138
|
+
{
|
|
139
|
+
return other.is_equal_to_primitive(*this);
|
|
140
|
+
}
|
|
141
|
+
// Step 10: Datacriptor or accessor descriptor
|
|
142
|
+
if (is_data_descriptor() || is_accessor_descriptor())
|
|
143
|
+
{
|
|
144
|
+
return (*this).is_strictly_equal_to_primitive(other);
|
|
145
|
+
}
|
|
146
|
+
// Step 11: All other cases (e.g., object == null) are false.
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const AnyValue AnyValue::is_strictly_equal_to(const AnyValue &other) const noexcept
|
|
151
|
+
{
|
|
152
|
+
return AnyValue::make_boolean(is_strictly_equal_to_primitive(other));
|
|
153
|
+
}
|
|
154
|
+
const AnyValue AnyValue::is_equal_to(const AnyValue &other) const noexcept
|
|
155
|
+
{
|
|
156
|
+
return AnyValue::make_boolean(is_equal_to_primitive(other));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const AnyValue AnyValue::not_strictly_equal_to(const AnyValue &other) const noexcept
|
|
160
|
+
{
|
|
161
|
+
return AnyValue::make_boolean(!is_strictly_equal_to_primitive(other));
|
|
162
|
+
}
|
|
163
|
+
const AnyValue AnyValue::not_equal_to(const AnyValue &other) const noexcept
|
|
164
|
+
{
|
|
165
|
+
return AnyValue::make_boolean(!is_equal_to_primitive(other));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const std::string AnyValue::to_std_string() const noexcept
|
|
169
|
+
{
|
|
170
|
+
switch (storage.type)
|
|
171
|
+
{
|
|
172
|
+
case JsType::Undefined:
|
|
173
|
+
return "undefined";
|
|
174
|
+
case JsType::Null:
|
|
175
|
+
return "null";
|
|
176
|
+
case JsType::Boolean:
|
|
177
|
+
return storage.boolean ? "true" : "false";
|
|
178
|
+
case JsType::String:
|
|
179
|
+
return storage.str->to_std_string();
|
|
180
|
+
case JsType::Object:
|
|
181
|
+
return storage.object->to_std_string();
|
|
182
|
+
case JsType::Array:
|
|
183
|
+
return storage.array->to_std_string();
|
|
184
|
+
case JsType::Function:
|
|
185
|
+
return storage.function->to_std_string();
|
|
186
|
+
case JsType::Iterator:
|
|
187
|
+
return storage.iterator->to_std_string();
|
|
188
|
+
case JsType::Promise:
|
|
189
|
+
return storage.promise->to_std_string();
|
|
190
|
+
case JsType::Symbol:
|
|
191
|
+
return storage.symbol->to_std_string();
|
|
192
|
+
case JsType::DataDescriptor:
|
|
193
|
+
return storage.data_desc->value->to_std_string();
|
|
194
|
+
case JsType::AccessorDescriptor:
|
|
195
|
+
{
|
|
196
|
+
if (storage.accessor_desc->get.has_value())
|
|
197
|
+
return storage.accessor_desc->get.value()(*this, {}).to_std_string();
|
|
198
|
+
else
|
|
199
|
+
return "undefined";
|
|
200
|
+
}
|
|
201
|
+
case JsType::Number:
|
|
202
|
+
{
|
|
203
|
+
if (std::isnan(storage.number))
|
|
204
|
+
{
|
|
205
|
+
return "NaN";
|
|
206
|
+
}
|
|
207
|
+
if (std::abs(storage.number) >= 1e21 || (std::abs(storage.number) > 0 && std::abs(storage.number) < 1e-6))
|
|
208
|
+
{
|
|
209
|
+
std::ostringstream oss;
|
|
210
|
+
oss << std::scientific << std::setprecision(4) << storage.number;
|
|
211
|
+
return oss.str();
|
|
212
|
+
}
|
|
213
|
+
else
|
|
214
|
+
{
|
|
215
|
+
std::ostringstream oss;
|
|
216
|
+
oss << std::setprecision(6) << std::fixed << storage.number;
|
|
217
|
+
std::string s = oss.str();
|
|
218
|
+
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
|
|
219
|
+
if (!s.empty() && s.back() == '.')
|
|
220
|
+
{
|
|
221
|
+
s.pop_back();
|
|
222
|
+
}
|
|
223
|
+
return s;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Uninitialized and default should not be reached under normal circumstances
|
|
227
|
+
case JsType::Uninitialized:
|
|
228
|
+
return "<uninitialized>";
|
|
229
|
+
default:
|
|
230
|
+
return "";
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
void AnyValue::set_prototype(const AnyValue &proto)
|
|
235
|
+
{
|
|
236
|
+
if (is_object())
|
|
237
|
+
{
|
|
238
|
+
storage.object->proto = std::make_shared<AnyValue>(proto);
|
|
239
|
+
}
|
|
240
|
+
else if (is_function())
|
|
241
|
+
{
|
|
242
|
+
storage.function->proto = std::make_shared<AnyValue>(proto);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#include "types.hpp"
|
|
5
|
+
|
|
6
|
+
namespace jspp
|
|
7
|
+
{
|
|
8
|
+
class AnyValue;
|
|
9
|
+
|
|
10
|
+
struct Exception : std::exception
|
|
11
|
+
{
|
|
12
|
+
std::shared_ptr<AnyValue> data;
|
|
13
|
+
|
|
14
|
+
explicit Exception(std::shared_ptr<AnyValue> d)
|
|
15
|
+
: data(std::move(d)) {}
|
|
16
|
+
explicit Exception(const AnyValue &value)
|
|
17
|
+
: data(std::make_shared<AnyValue>(value)) {}
|
|
18
|
+
explicit Exception(AnyValue &&value)
|
|
19
|
+
: data(std::make_shared<AnyValue>(std::move(value))) {}
|
|
20
|
+
|
|
21
|
+
const char *what() const noexcept override;
|
|
22
|
+
static Exception make_exception(const std::string &message, const std::string &name);
|
|
23
|
+
static AnyValue exception_to_any_value(const std::exception &ex);
|
|
24
|
+
|
|
25
|
+
// --- THROWERS
|
|
26
|
+
static AnyValue throw_unresolved_reference(const std::string &var_name);
|
|
27
|
+
static AnyValue throw_uninitialized_reference(const std::string &var_name);
|
|
28
|
+
static AnyValue throw_immutable_assignment();
|
|
29
|
+
static AnyValue throw_invalid_return_statement();
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "exception.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
|
|
7
|
+
const char *jspp::Exception::what() const noexcept
|
|
8
|
+
{
|
|
9
|
+
return data->to_std_string().c_str();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
jspp::Exception jspp::Exception::make_exception(const std::string &message, const std::string &name = "Error")
|
|
13
|
+
{
|
|
14
|
+
// Use the global Error object to construct the exception
|
|
15
|
+
std::vector<AnyValue> args = { AnyValue::make_string(message) };
|
|
16
|
+
AnyValue errorObj = ::Error.construct(args);
|
|
17
|
+
errorObj.define_data_property("name", AnyValue::make_string(name));
|
|
18
|
+
|
|
19
|
+
return Exception(errorObj);
|
|
20
|
+
}
|
|
21
|
+
jspp::AnyValue jspp::Exception::exception_to_any_value(const std::exception &ex)
|
|
22
|
+
{
|
|
23
|
+
if (const jspp::Exception *err = dynamic_cast<const jspp::Exception *>(&ex))
|
|
24
|
+
{
|
|
25
|
+
return (*err->data);
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
{
|
|
29
|
+
return AnyValue::make_string(ex.what());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// --- THROWERS
|
|
34
|
+
jspp::AnyValue jspp::Exception::throw_unresolved_reference(const std::string &var_name)
|
|
35
|
+
{
|
|
36
|
+
throw Exception::make_exception(var_name + " is not defined", "ReferenceError");
|
|
37
|
+
}
|
|
38
|
+
jspp::AnyValue jspp::Exception::throw_uninitialized_reference(const std::string &var_name)
|
|
39
|
+
{
|
|
40
|
+
throw Exception::make_exception("Cannot access '" + var_name + "' before initialization", "ReferenceError");
|
|
41
|
+
}
|
|
42
|
+
jspp::AnyValue jspp::Exception::throw_immutable_assignment()
|
|
43
|
+
{
|
|
44
|
+
throw Exception::make_exception("Assignment to constant variable.", "TypeError");
|
|
45
|
+
}
|
|
46
|
+
jspp::AnyValue jspp::Exception::throw_invalid_return_statement()
|
|
47
|
+
{
|
|
48
|
+
throw Exception::make_exception("Return statements are only valid inside functions.", "SyntaxError");
|
|
49
|
+
}
|
package/src/prelude/index.hpp
CHANGED
|
@@ -1,29 +1,52 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
|
-
#include "well_known_symbols.hpp"
|
|
4
|
+
#include "utils/well_known_symbols.hpp"
|
|
5
5
|
|
|
6
6
|
// values
|
|
7
|
+
#include "values/symbol.hpp"
|
|
7
8
|
#include "values/non_values.hpp"
|
|
8
9
|
#include "values/object.hpp"
|
|
9
10
|
#include "values/array.hpp"
|
|
10
11
|
#include "values/function.hpp"
|
|
11
|
-
#include "
|
|
12
|
-
#include "
|
|
12
|
+
#include "values/iterator.hpp"
|
|
13
|
+
#include "values/promise.hpp"
|
|
14
|
+
#include "values/string.hpp"
|
|
15
|
+
|
|
16
|
+
#include "exception.hpp"
|
|
17
|
+
#include "values/descriptors.hpp"
|
|
13
18
|
#include "any_value.hpp"
|
|
14
|
-
#include "
|
|
15
|
-
#include "
|
|
19
|
+
#include "any_value_helpers.hpp"
|
|
20
|
+
#include "any_value_access.hpp"
|
|
21
|
+
#include "any_value_defines.hpp"
|
|
22
|
+
#include "library/error.hpp"
|
|
23
|
+
#include "exception_helpers.hpp"
|
|
24
|
+
#include "scheduler.hpp"
|
|
25
|
+
|
|
26
|
+
#include "values/prototypes/symbol.hpp"
|
|
16
27
|
#include "values/prototypes/object.hpp"
|
|
17
28
|
#include "values/prototypes/array.hpp"
|
|
18
29
|
#include "values/prototypes/function.hpp"
|
|
19
|
-
#include "values/
|
|
20
|
-
#include "values/
|
|
21
|
-
#include "values/
|
|
30
|
+
#include "values/prototypes/iterator.hpp"
|
|
31
|
+
#include "values/prototypes/promise.hpp"
|
|
32
|
+
#include "values/prototypes/string.hpp"
|
|
33
|
+
|
|
34
|
+
#include "values/helpers/symbol.hpp"
|
|
35
|
+
#include "values/helpers/object.hpp"
|
|
36
|
+
#include "values/helpers/array.hpp"
|
|
37
|
+
#include "values/helpers/function.hpp"
|
|
38
|
+
#include "values/helpers/iterator.hpp"
|
|
39
|
+
#include "values/helpers/promise.hpp"
|
|
40
|
+
#include "values/helpers/string.hpp"
|
|
22
41
|
|
|
23
|
-
//
|
|
24
|
-
#include "operators.hpp"
|
|
25
|
-
#include "access.hpp"
|
|
26
|
-
#include "
|
|
42
|
+
// utilities
|
|
43
|
+
#include "utils/operators.hpp"
|
|
44
|
+
#include "utils/access.hpp"
|
|
45
|
+
#include "utils/log_any_value/log_any_value.hpp"
|
|
27
46
|
|
|
28
47
|
// js standard libraries
|
|
48
|
+
#include "library/symbol.hpp"
|
|
29
49
|
#include "library/console.hpp"
|
|
50
|
+
#include "library/performance.hpp"
|
|
51
|
+
#include "library/promise.hpp"
|
|
52
|
+
#include "library/global.hpp"
|