@ugo-studio/jspp 0.1.2 → 0.1.3
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 +3 -1
- package/dist/analysis/scope.js +22 -11
- package/dist/analysis/typeAnalyzer.js +4 -3
- package/dist/cli.js +2 -2
- package/dist/core/codegen/expression-handlers.js +10 -6
- package/dist/core/codegen/function-handlers.js +27 -6
- package/dist/core/codegen/helpers.js +12 -8
- package/dist/core/codegen/index.js +3 -1
- package/dist/core/codegen/statement-handlers.js +53 -16
- package/dist/core/codegen/visitor.js +7 -1
- package/package.json +1 -1
- package/src/prelude/access.hpp +8 -3
- package/src/prelude/any_value.hpp +141 -241
- package/src/prelude/any_value_helpers.hpp +225 -0
- package/src/prelude/error_helpers.hpp +3 -3
- package/src/prelude/index.hpp +17 -3
- package/src/prelude/library/console.hpp +7 -7
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/symbol.hpp +60 -3
- package/src/prelude/log_string.hpp +10 -6
- package/src/prelude/operators.hpp +2 -2
- package/src/prelude/types.hpp +24 -6
- package/src/prelude/values/array.hpp +2 -0
- package/src/prelude/values/function.hpp +33 -1
- package/src/prelude/values/{operators → helpers}/array.hpp +14 -7
- package/src/prelude/values/helpers/function.hpp +77 -0
- package/src/prelude/values/helpers/iterator.hpp +101 -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 +88 -0
- package/src/prelude/values/object.hpp +2 -1
- package/src/prelude/values/prototypes/array.hpp +18 -11
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +57 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +39 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/well_known_symbols.hpp +7 -3
- package/src/prelude/values/operators/function.hpp +0 -34
- /package/src/prelude/values/{operators → helpers}/object.hpp +0 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
#include "values/string.hpp"
|
|
6
|
+
|
|
7
|
+
const bool jspp::AnyValue::is_truthy() const noexcept
|
|
8
|
+
{
|
|
9
|
+
switch (storage.type)
|
|
10
|
+
{
|
|
11
|
+
case JsType::Boolean:
|
|
12
|
+
return storage.boolean;
|
|
13
|
+
case JsType::Number:
|
|
14
|
+
return storage.number != 0.0;
|
|
15
|
+
case JsType::String:
|
|
16
|
+
return !storage.str->value.empty();
|
|
17
|
+
case JsType::Undefined:
|
|
18
|
+
return false;
|
|
19
|
+
case JsType::Null:
|
|
20
|
+
return false;
|
|
21
|
+
case JsType::Uninitialized:
|
|
22
|
+
return false;
|
|
23
|
+
default:
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const bool jspp::AnyValue::is_strictly_equal_to(const AnyValue &other) const noexcept
|
|
29
|
+
{
|
|
30
|
+
if (storage.type == other.storage.type)
|
|
31
|
+
{
|
|
32
|
+
switch (storage.type)
|
|
33
|
+
{
|
|
34
|
+
case JsType::Boolean:
|
|
35
|
+
return storage.boolean == other.storage.boolean;
|
|
36
|
+
case JsType::Number:
|
|
37
|
+
return storage.number == other.storage.number;
|
|
38
|
+
case JsType::String:
|
|
39
|
+
return (storage.str->value == other.storage.str->value);
|
|
40
|
+
case JsType::Array:
|
|
41
|
+
return (storage.array == other.storage.array);
|
|
42
|
+
case JsType::Object:
|
|
43
|
+
return (storage.object == other.storage.object);
|
|
44
|
+
case JsType::Function:
|
|
45
|
+
return (storage.function == other.storage.function);
|
|
46
|
+
case JsType::Symbol:
|
|
47
|
+
// Symbols are unique by reference/pointer identity
|
|
48
|
+
return (storage.symbol == other.storage.symbol);
|
|
49
|
+
case JsType::DataDescriptor:
|
|
50
|
+
return (resolve_property_for_read(*this).is_strictly_equal_to(resolve_property_for_read(other)));
|
|
51
|
+
case JsType::AccessorDescriptor:
|
|
52
|
+
return (resolve_property_for_read(*this).is_strictly_equal_to(resolve_property_for_read(other)));
|
|
53
|
+
default:
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const bool jspp::AnyValue::is_equal_to(const AnyValue &other) const noexcept
|
|
60
|
+
{
|
|
61
|
+
// Implements JavaScript's Abstract Equality Comparison Algorithm (==)
|
|
62
|
+
// Step 1: If types are the same, use strict equality (===)
|
|
63
|
+
if (storage.type == other.storage.type)
|
|
64
|
+
{
|
|
65
|
+
return is_strictly_equal_to(other);
|
|
66
|
+
}
|
|
67
|
+
// Steps 2 & 3: null == undefined
|
|
68
|
+
if ((is_null() && other.is_undefined()) || (is_undefined() && other.is_null()))
|
|
69
|
+
{
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
// Step 4 & 5: number == string
|
|
73
|
+
if (is_number() && other.is_string())
|
|
74
|
+
{
|
|
75
|
+
double num_this = this->as_double();
|
|
76
|
+
double num_other;
|
|
77
|
+
try
|
|
78
|
+
{
|
|
79
|
+
const std::string &s = other.as_string()->value;
|
|
80
|
+
// JS considers empty string or whitespace-only string to be 0
|
|
81
|
+
if (s.empty() || std::all_of(s.begin(), s.end(), [](unsigned char c)
|
|
82
|
+
{ return std::isspace(c); }))
|
|
83
|
+
{
|
|
84
|
+
num_other = 0.0;
|
|
85
|
+
}
|
|
86
|
+
else
|
|
87
|
+
{
|
|
88
|
+
size_t pos;
|
|
89
|
+
num_other = std::stod(s, &pos);
|
|
90
|
+
// Check if the entire string was consumed, allowing for trailing whitespace
|
|
91
|
+
while (pos < s.length() && std::isspace(static_cast<unsigned char>(s[pos])))
|
|
92
|
+
{
|
|
93
|
+
pos++;
|
|
94
|
+
}
|
|
95
|
+
if (pos != s.length())
|
|
96
|
+
{
|
|
97
|
+
num_other = std::numeric_limits<double>::quiet_NaN();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (...)
|
|
102
|
+
{
|
|
103
|
+
num_other = std::numeric_limits<double>::quiet_NaN();
|
|
104
|
+
}
|
|
105
|
+
return num_this == num_other;
|
|
106
|
+
}
|
|
107
|
+
if (is_string() && other.is_number())
|
|
108
|
+
{
|
|
109
|
+
// Delegate to the other operand to avoid code duplication
|
|
110
|
+
return other.is_equal_to(*this);
|
|
111
|
+
}
|
|
112
|
+
// Step 6 & 7: boolean == any
|
|
113
|
+
if (is_boolean())
|
|
114
|
+
{
|
|
115
|
+
// Convert boolean to number and re-compare
|
|
116
|
+
return AnyValue::make_number(as_boolean() ? 1.0 : 0.0).is_equal_to(other);
|
|
117
|
+
}
|
|
118
|
+
if (other.is_boolean())
|
|
119
|
+
{
|
|
120
|
+
// Convert boolean to number and re-compare
|
|
121
|
+
return is_equal_to(AnyValue::make_number(other.as_boolean() ? 1.0 : 0.0));
|
|
122
|
+
}
|
|
123
|
+
// Step 8 & 9: object == (string or number or symbol)
|
|
124
|
+
// Simplified: Objects convert to primitives.
|
|
125
|
+
if ((is_object() || is_array() || is_function()) && (other.is_string() || other.is_number() || other.is_symbol()))
|
|
126
|
+
{
|
|
127
|
+
// Convert object to primitive (string) and re-compare.
|
|
128
|
+
// This is a simplification of JS's ToPrimitive.
|
|
129
|
+
return AnyValue::make_string(to_std_string()).is_equal_to(other);
|
|
130
|
+
}
|
|
131
|
+
if ((other.is_object() || other.is_array() || other.is_function()) && (is_string() || is_number() || is_symbol()))
|
|
132
|
+
{
|
|
133
|
+
return other.is_equal_to(*this);
|
|
134
|
+
}
|
|
135
|
+
// Step 10: Parse datacriptor or accessor descriptor to primitive and re-compare
|
|
136
|
+
if (is_data_descriptor() || is_accessor_descriptor())
|
|
137
|
+
{
|
|
138
|
+
AnyValue prim = resolve_property_for_read(*this);
|
|
139
|
+
return prim.is_equal_to(other);
|
|
140
|
+
}
|
|
141
|
+
// Step 11: All other cases (e.g., object == null) are false.
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const jspp::AnyValue jspp::AnyValue::is_strictly_equal_to_primitive(const AnyValue &other) const noexcept
|
|
146
|
+
{
|
|
147
|
+
return AnyValue::make_boolean(is_strictly_equal_to(other));
|
|
148
|
+
}
|
|
149
|
+
const jspp::AnyValue jspp::AnyValue::is_equal_to_primitive(const AnyValue &other) const noexcept
|
|
150
|
+
{
|
|
151
|
+
return AnyValue::make_boolean(is_equal_to(other));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const jspp::AnyValue jspp::AnyValue::not_strictly_equal_to_primitive(const AnyValue &other) const noexcept
|
|
155
|
+
{
|
|
156
|
+
return AnyValue::make_boolean(!is_strictly_equal_to(other));
|
|
157
|
+
}
|
|
158
|
+
const jspp::AnyValue jspp::AnyValue::not_equal_to_primitive(const AnyValue &other) const noexcept
|
|
159
|
+
{
|
|
160
|
+
return AnyValue::make_boolean(!is_equal_to(other));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const std::string jspp::AnyValue::to_std_string() const noexcept
|
|
164
|
+
{
|
|
165
|
+
switch (storage.type)
|
|
166
|
+
{
|
|
167
|
+
case JsType::Undefined:
|
|
168
|
+
return "undefined";
|
|
169
|
+
case JsType::Null:
|
|
170
|
+
return "null";
|
|
171
|
+
case JsType::Boolean:
|
|
172
|
+
return storage.boolean ? "true" : "false";
|
|
173
|
+
case JsType::String:
|
|
174
|
+
return storage.str->to_std_string();
|
|
175
|
+
case JsType::Object:
|
|
176
|
+
return storage.object->to_std_string();
|
|
177
|
+
case JsType::Array:
|
|
178
|
+
return storage.array->to_std_string();
|
|
179
|
+
case JsType::Function:
|
|
180
|
+
return storage.function->to_std_string();
|
|
181
|
+
case JsType::Iterator:
|
|
182
|
+
return storage.iterator->to_std_string();
|
|
183
|
+
case JsType::Symbol:
|
|
184
|
+
return storage.symbol->to_std_string();
|
|
185
|
+
case JsType::DataDescriptor:
|
|
186
|
+
return storage.data_desc->value->to_std_string();
|
|
187
|
+
case JsType::AccessorDescriptor:
|
|
188
|
+
{
|
|
189
|
+
if (storage.accessor_desc->get.has_value())
|
|
190
|
+
return storage.accessor_desc->get.value()({}).to_std_string();
|
|
191
|
+
else
|
|
192
|
+
return "undefined";
|
|
193
|
+
}
|
|
194
|
+
case JsType::Number:
|
|
195
|
+
{
|
|
196
|
+
if (std::isnan(storage.number))
|
|
197
|
+
{
|
|
198
|
+
return "NaN";
|
|
199
|
+
}
|
|
200
|
+
if (std::abs(storage.number) >= 1e21 || (std::abs(storage.number) > 0 && std::abs(storage.number) < 1e-6))
|
|
201
|
+
{
|
|
202
|
+
std::ostringstream oss;
|
|
203
|
+
oss << std::scientific << std::setprecision(4) << storage.number;
|
|
204
|
+
return oss.str();
|
|
205
|
+
}
|
|
206
|
+
else
|
|
207
|
+
{
|
|
208
|
+
std::ostringstream oss;
|
|
209
|
+
oss << std::setprecision(6) << std::fixed << storage.number;
|
|
210
|
+
std::string s = oss.str();
|
|
211
|
+
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
|
|
212
|
+
if (!s.empty() && s.back() == '.')
|
|
213
|
+
{
|
|
214
|
+
s.pop_back();
|
|
215
|
+
}
|
|
216
|
+
return s;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Uninitialized and default should not be reached under normal circumstances
|
|
220
|
+
case JsType::Uninitialized:
|
|
221
|
+
return "<uninitialized>";
|
|
222
|
+
default:
|
|
223
|
+
return "";
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -12,8 +12,8 @@ const char *jspp::RuntimeError::what() const noexcept
|
|
|
12
12
|
jspp::RuntimeError jspp::RuntimeError::make_error(const std::string &message, const std::string &name = "Error")
|
|
13
13
|
{
|
|
14
14
|
auto errorObj = std::make_shared<AnyValue>(AnyValue::make_object({{"message", AnyValue::make_string(message)}, {"name", AnyValue::make_string(name)}}));
|
|
15
|
-
(*errorObj).set_own_property(WellKnownSymbols::toString, AnyValue::make_function([errorObj](const std::vector<AnyValue> &) -> AnyValue
|
|
16
|
-
|
|
15
|
+
(*errorObj).set_own_property(WellKnownSymbols::toString->key, AnyValue::make_function([errorObj](const std::vector<AnyValue> &) -> AnyValue
|
|
16
|
+
{
|
|
17
17
|
AnyValue name = (*errorObj).get_own_property("name");
|
|
18
18
|
AnyValue message = (*errorObj).get_own_property("message");
|
|
19
19
|
std::string str = "";
|
|
@@ -25,7 +25,7 @@ jspp::RuntimeError jspp::RuntimeError::make_error(const std::string &message, co
|
|
|
25
25
|
if (message.is_string())
|
|
26
26
|
str += message.to_std_string();
|
|
27
27
|
return AnyValue::make_string(str); },
|
|
28
|
-
|
|
28
|
+
WellKnownSymbols::toString->key));
|
|
29
29
|
return RuntimeError(errorObj);
|
|
30
30
|
}
|
|
31
31
|
jspp::AnyValue jspp::RuntimeError::error_to_value(const std::exception &ex)
|
package/src/prelude/index.hpp
CHANGED
|
@@ -4,21 +4,33 @@
|
|
|
4
4
|
#include "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"
|
|
12
|
+
#include "values/iterator.hpp"
|
|
13
|
+
#include "values/string.hpp"
|
|
14
|
+
|
|
11
15
|
#include "error.hpp"
|
|
12
16
|
#include "descriptors.hpp"
|
|
13
17
|
#include "any_value.hpp"
|
|
18
|
+
#include "any_value_helpers.hpp"
|
|
14
19
|
#include "error_helpers.hpp"
|
|
20
|
+
|
|
21
|
+
#include "values/prototypes/symbol.hpp"
|
|
15
22
|
#include "values/prototypes/string.hpp"
|
|
16
23
|
#include "values/prototypes/object.hpp"
|
|
17
24
|
#include "values/prototypes/array.hpp"
|
|
18
25
|
#include "values/prototypes/function.hpp"
|
|
19
|
-
#include "values/
|
|
20
|
-
|
|
21
|
-
#include "values/
|
|
26
|
+
#include "values/prototypes/iterator.hpp"
|
|
27
|
+
|
|
28
|
+
#include "values/helpers/symbol.hpp"
|
|
29
|
+
#include "values/helpers/object.hpp"
|
|
30
|
+
#include "values/helpers/array.hpp"
|
|
31
|
+
#include "values/helpers/function.hpp"
|
|
32
|
+
#include "values/helpers/iterator.hpp"
|
|
33
|
+
#include "values/helpers/string.hpp"
|
|
22
34
|
|
|
23
35
|
// helpers
|
|
24
36
|
#include "operators.hpp"
|
|
@@ -26,4 +38,6 @@
|
|
|
26
38
|
#include "log_string.hpp"
|
|
27
39
|
|
|
28
40
|
// js standard libraries
|
|
41
|
+
#include "library/symbol.hpp"
|
|
29
42
|
#include "library/console.hpp"
|
|
43
|
+
#include "library/performance.hpp"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include
|
|
3
|
+
#include <chrono>
|
|
4
4
|
#include "types.hpp"
|
|
5
5
|
#include "values/non_values.hpp"
|
|
6
6
|
#include "values/object.hpp"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
#include <sstream>
|
|
13
13
|
#include <iomanip>
|
|
14
14
|
|
|
15
|
-
static std::
|
|
15
|
+
static std::map<std::string, std::chrono::steady_clock::time_point> timers = {};
|
|
16
16
|
|
|
17
17
|
auto logFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue> &args)
|
|
18
18
|
{
|
|
@@ -23,7 +23,7 @@ auto logFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue>
|
|
|
23
23
|
std::cout << " ";
|
|
24
24
|
}
|
|
25
25
|
std::cout << "\n";
|
|
26
|
-
return jspp::AnyValue::make_undefined(); }, "");
|
|
26
|
+
return jspp::AnyValue::make_undefined(); }, "log");
|
|
27
27
|
auto warnFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue> &args)
|
|
28
28
|
{
|
|
29
29
|
std::cerr << "\033[33m";
|
|
@@ -34,7 +34,7 @@ auto warnFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue>
|
|
|
34
34
|
std::cout << " ";
|
|
35
35
|
}
|
|
36
36
|
std::cerr << "\033[0m" << "\n"; // reset
|
|
37
|
-
return jspp::AnyValue::make_undefined(); }, "");
|
|
37
|
+
return jspp::AnyValue::make_undefined(); }, "warn");
|
|
38
38
|
auto errorFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue> &args)
|
|
39
39
|
{
|
|
40
40
|
std::cerr << "\033[31m";
|
|
@@ -45,13 +45,13 @@ auto errorFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue
|
|
|
45
45
|
std::cout << " ";
|
|
46
46
|
}
|
|
47
47
|
std::cerr << "\033[0m" << "\n"; // reset
|
|
48
|
-
return jspp::AnyValue::make_undefined(); }, "");
|
|
48
|
+
return jspp::AnyValue::make_undefined(); }, "error");
|
|
49
49
|
auto timeFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue> &args)
|
|
50
50
|
{
|
|
51
51
|
auto start = std::chrono::steady_clock::now(); // capture immediately
|
|
52
52
|
auto key_str = args.size() > 0 ? args[0].to_std_string() : "default";
|
|
53
53
|
timers[key_str] = start;
|
|
54
|
-
return jspp::AnyValue::make_undefined(); }, "");
|
|
54
|
+
return jspp::AnyValue::make_undefined(); }, "time");
|
|
55
55
|
|
|
56
56
|
// helper to format duration in ms -> ms/s/m/h with nice precision
|
|
57
57
|
static auto format_duration = [](double ms) -> std::string
|
|
@@ -100,7 +100,7 @@ auto timeEndFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyVal
|
|
|
100
100
|
{
|
|
101
101
|
std::cout << "Timer '" << key_str << "' does not exist." << "\n";
|
|
102
102
|
}
|
|
103
|
-
return jspp::AnyValue::make_undefined(); }, "");
|
|
103
|
+
return jspp::AnyValue::make_undefined(); }, "timeEnd");
|
|
104
104
|
|
|
105
105
|
inline auto console = jspp::AnyValue::make_object({
|
|
106
106
|
{"log", logFn},
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <chrono>
|
|
4
|
+
#include "types.hpp"
|
|
5
|
+
#include "values/non_values.hpp"
|
|
6
|
+
#include "values/object.hpp"
|
|
7
|
+
#include "values/function.hpp"
|
|
8
|
+
#include "operators.hpp"
|
|
9
|
+
|
|
10
|
+
inline auto performance = jspp::AnyValue::make_object({
|
|
11
|
+
{"now",
|
|
12
|
+
jspp::AnyValue::make_function(
|
|
13
|
+
// [C++14 Feature] Generalized Lambda Capture
|
|
14
|
+
// We initialize 'startTime' RIGHT HERE inside the [].
|
|
15
|
+
// It acts like a private variable stored inside this specific function.
|
|
16
|
+
[startTime = std::chrono::steady_clock::now()](const std::vector<jspp::AnyValue> &)
|
|
17
|
+
{
|
|
18
|
+
// We calculate the diff against the captured startTime
|
|
19
|
+
std::chrono::duration<double, std::milli> duration =
|
|
20
|
+
std::chrono::steady_clock::now() - startTime;
|
|
21
|
+
|
|
22
|
+
return jspp::AnyValue::make_number(duration.count());
|
|
23
|
+
},
|
|
24
|
+
"now")},
|
|
25
|
+
});
|
|
@@ -1,8 +1,65 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
|
-
#include "object.hpp"
|
|
5
4
|
#include "well_known_symbols.hpp"
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
#include "values/object.hpp"
|
|
7
|
+
#include "any_value.hpp"
|
|
8
|
+
|
|
9
|
+
inline auto Symbol = jspp::AnyValue::make_object({
|
|
10
|
+
{"iterator", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::iterator)},
|
|
11
|
+
{"toString", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::toString)},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// #pragma once
|
|
15
|
+
|
|
16
|
+
// #include "types.hpp"
|
|
17
|
+
// #include "well_known_symbols.hpp"
|
|
18
|
+
// #include "values/object.hpp"
|
|
19
|
+
// #include "any_value.hpp"
|
|
20
|
+
|
|
21
|
+
// // We define the Symbol constructor function
|
|
22
|
+
// inline auto symbolConstructor = [](const std::vector<jspp::AnyValue>& args) -> jspp::AnyValue {
|
|
23
|
+
// std::string desc = "";
|
|
24
|
+
// if (!args.empty() && !args[0].is_undefined()) {
|
|
25
|
+
// desc = args[0].to_std_string();
|
|
26
|
+
// }
|
|
27
|
+
// return jspp::AnyValue::make_symbol(desc);
|
|
28
|
+
// };
|
|
29
|
+
|
|
30
|
+
// inline auto Symbol = jspp::AnyValue::make_function(symbolConstructor, "Symbol");
|
|
31
|
+
|
|
32
|
+
// // Implementation of Symbol.for(key)
|
|
33
|
+
// inline auto forFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue>& args) -> jspp::AnyValue {
|
|
34
|
+
// std::string key = "";
|
|
35
|
+
// if (!args.empty()) {
|
|
36
|
+
// key = args[0].to_std_string();
|
|
37
|
+
// }
|
|
38
|
+
// auto symPtr = jspp::JsSymbol::for_global(key);
|
|
39
|
+
// return jspp::AnyValue::from_symbol(symPtr);
|
|
40
|
+
// }, "for");
|
|
41
|
+
|
|
42
|
+
// // Implementation of Symbol.keyFor(sym)
|
|
43
|
+
// inline auto keyForFn = jspp::AnyValue::make_function([](const std::vector<jspp::AnyValue>& args) -> jspp::AnyValue {
|
|
44
|
+
// if (args.empty() || !args[0].is_symbol()) {
|
|
45
|
+
// throw jspp::RuntimeError::make_error("Symbol.keyFor requires a symbol argument", "TypeError");
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// jspp::JsSymbol* sym = args[0].as_symbol();
|
|
49
|
+
// auto result = jspp::JsSymbol::key_for(sym);
|
|
50
|
+
|
|
51
|
+
// if (result.has_value()) {
|
|
52
|
+
// return jspp::AnyValue::make_string(result.value());
|
|
53
|
+
// } else {
|
|
54
|
+
// return jspp::AnyValue::make_undefined();
|
|
55
|
+
// }
|
|
56
|
+
// }, "keyFor");
|
|
57
|
+
|
|
58
|
+
// // Attach static properties/methods to the Symbol object
|
|
59
|
+
// struct SymbolInit {
|
|
60
|
+
// SymbolInit() {
|
|
61
|
+
// Symbol.set_own_property("iterator", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::iterator));
|
|
62
|
+
// Symbol.set_own_property("for", forFn);
|
|
63
|
+
// Symbol.set_own_property("keyFor", keyForFn);
|
|
64
|
+
// }
|
|
65
|
+
// } symbolInit;
|
|
@@ -26,6 +26,7 @@ namespace jspp
|
|
|
26
26
|
const std::string RESET = "\033[0m";
|
|
27
27
|
const std::string GREEN = "\033[32m";
|
|
28
28
|
const std::string YELLOW = "\033[33m";
|
|
29
|
+
const std::string BLUE = "\033[94m";
|
|
29
30
|
const std::string CYAN = "\033[36m";
|
|
30
31
|
const std::string MAGENTA = "\033[35m";
|
|
31
32
|
const std::string BRIGHT_BLACK = "\033[90m"; // Grey
|
|
@@ -90,9 +91,11 @@ namespace jspp
|
|
|
90
91
|
return Color::YELLOW + std::string(val.as_boolean() ? "true" : "false") + Color::RESET;
|
|
91
92
|
if (val.is_number())
|
|
92
93
|
return Color::YELLOW + val.to_std_string() + Color::RESET;
|
|
94
|
+
if (val.is_symbol())
|
|
95
|
+
return Color::BLUE + val.to_std_string() + Color::RESET;
|
|
93
96
|
if (val.is_string())
|
|
94
97
|
{
|
|
95
|
-
const std::string &s =
|
|
98
|
+
const std::string &s = val.as_string()->value;
|
|
96
99
|
if (depth == 0)
|
|
97
100
|
return truncate_string(s);
|
|
98
101
|
return Color::GREEN + std::string("\"") + truncate_string(s) + "\"" + Color::RESET;
|
|
@@ -100,8 +103,9 @@ namespace jspp
|
|
|
100
103
|
if (val.is_function())
|
|
101
104
|
{
|
|
102
105
|
auto fn = val.as_function();
|
|
106
|
+
auto type_part = fn->is_generator ? "GeneratorFunction" : "Function";
|
|
103
107
|
auto name_part = fn->name.size() > 0 ? ": " + fn->name : "";
|
|
104
|
-
return Color::CYAN +
|
|
108
|
+
return Color::CYAN + "[" + type_part + name_part + "]" + Color::RESET;
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
// Depth limit
|
|
@@ -137,12 +141,12 @@ namespace jspp
|
|
|
137
141
|
auto obj = val.as_object();
|
|
138
142
|
|
|
139
143
|
// If custom toString exists on the object, prefer it
|
|
140
|
-
auto itToString = obj->props.find(jspp::WellKnownSymbols::toString);
|
|
144
|
+
auto itToString = obj->props.find(jspp::WellKnownSymbols::toString->key);
|
|
141
145
|
if (itToString != obj->props.end() && itToString->second.is_function())
|
|
142
146
|
{
|
|
143
147
|
try
|
|
144
148
|
{
|
|
145
|
-
auto result = itToString->second.as_function(
|
|
149
|
+
auto result = itToString->second.as_function()->call({});
|
|
146
150
|
return to_log_string(result, visited, depth);
|
|
147
151
|
}
|
|
148
152
|
catch (...)
|
|
@@ -230,12 +234,12 @@ namespace jspp
|
|
|
230
234
|
size_t item_count = static_cast<size_t>(arr->length);
|
|
231
235
|
|
|
232
236
|
// If custom toString exists on the object, prefer it
|
|
233
|
-
auto itToString = arr->props.find(jspp::WellKnownSymbols::toString);
|
|
237
|
+
auto itToString = arr->props.find(jspp::WellKnownSymbols::toString->key);
|
|
234
238
|
if (depth > 0 && itToString != arr->props.end() && itToString->second.is_function())
|
|
235
239
|
{
|
|
236
240
|
try
|
|
237
241
|
{
|
|
238
|
-
auto result = itToString->second.as_function(
|
|
242
|
+
auto result = itToString->second.as_function()->call({});
|
|
239
243
|
return to_log_string(result, visited, depth);
|
|
240
244
|
}
|
|
241
245
|
catch (...)
|
|
@@ -23,7 +23,7 @@ namespace jspp
|
|
|
23
23
|
return val.as_boolean() ? 1.0 : 0.0;
|
|
24
24
|
if (val.is_string())
|
|
25
25
|
{
|
|
26
|
-
const std::string &s =
|
|
26
|
+
const std::string &s = val.as_string()->value;
|
|
27
27
|
// JS considers empty or whitespace-only strings as 0.
|
|
28
28
|
if (s.empty() || std::all_of(s.begin(), s.end(), isspace))
|
|
29
29
|
return 0.0;
|
|
@@ -116,7 +116,7 @@ namespace jspp
|
|
|
116
116
|
{
|
|
117
117
|
// Simplified Abstract Relational Comparison
|
|
118
118
|
if (lhs.is_string() && rhs.is_string())
|
|
119
|
-
return AnyValue::make_boolean(
|
|
119
|
+
return AnyValue::make_boolean(lhs.as_string()->value < rhs.as_string()->value);
|
|
120
120
|
|
|
121
121
|
double l = Operators_Private::ToNumber(lhs);
|
|
122
122
|
double r = Operators_Private::ToNumber(rhs);
|
package/src/prelude/types.hpp
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#include <variant>
|
|
7
7
|
#include <functional>
|
|
8
8
|
#include <memory>
|
|
9
|
+
#include <map>
|
|
9
10
|
#include <unordered_map>
|
|
10
11
|
#include <algorithm>
|
|
11
12
|
#include <cctype>
|
|
@@ -17,34 +18,51 @@
|
|
|
17
18
|
// JSPP standard library
|
|
18
19
|
namespace jspp
|
|
19
20
|
{
|
|
20
|
-
//
|
|
21
|
+
// Js value forward declarations
|
|
21
22
|
struct JsUndefined; // cannot set property
|
|
22
23
|
struct JsNull; // cannot set property
|
|
23
24
|
struct JsUninitialized; // cannot set property
|
|
25
|
+
struct JsString; // can set property
|
|
24
26
|
struct JsObject; // can set property
|
|
25
27
|
struct JsArray; // can set property
|
|
26
28
|
struct JsFunction; // can set property
|
|
29
|
+
struct JsSymbol; // can set property (but usually doesn't have own props)
|
|
30
|
+
|
|
31
|
+
template <typename T>
|
|
32
|
+
class JsIterator; // can set property
|
|
27
33
|
|
|
28
34
|
// Object property configuration forward declarations
|
|
29
35
|
struct DataDescriptor;
|
|
30
36
|
struct AccessorDescriptor;
|
|
31
37
|
|
|
32
|
-
// Dynamic AnyValue
|
|
33
|
-
class AnyValue;
|
|
34
|
-
|
|
35
38
|
// Custom runtime exception
|
|
36
39
|
struct RuntimeError;
|
|
37
40
|
|
|
41
|
+
// Dynamic AnyValue
|
|
42
|
+
class AnyValue;
|
|
43
|
+
|
|
38
44
|
// Arithemetic operators
|
|
39
45
|
inline AnyValue pow(const AnyValue &lhs, const AnyValue &rhs);
|
|
40
46
|
|
|
41
47
|
// AnyValue prototypes
|
|
42
48
|
namespace StringPrototypes
|
|
43
49
|
{
|
|
44
|
-
inline std::optional<AnyValue> get(const std::string &key,
|
|
50
|
+
inline std::optional<AnyValue> get(const std::string &key, JsString *self);
|
|
45
51
|
}
|
|
46
52
|
namespace ArrayPrototypes
|
|
47
53
|
{
|
|
48
54
|
inline std::optional<AnyValue> get(const std::string &key, JsArray *self);
|
|
49
55
|
}
|
|
50
|
-
|
|
56
|
+
namespace FunctionPrototypes
|
|
57
|
+
{
|
|
58
|
+
inline std::optional<AnyValue> get(const std::string &key, JsFunction *self);
|
|
59
|
+
}
|
|
60
|
+
namespace IteratorPrototypes
|
|
61
|
+
{
|
|
62
|
+
inline std::optional<AnyValue> get(const std::string &key, JsIterator<AnyValue> *self);
|
|
63
|
+
}
|
|
64
|
+
namespace SymbolPrototypes
|
|
65
|
+
{
|
|
66
|
+
inline std::optional<AnyValue> get(const std::string &key, JsSymbol *self);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
namespace jspp
|
|
7
7
|
{
|
|
8
|
+
// Forward declaration of AnyValue
|
|
8
9
|
class AnyValue;
|
|
9
10
|
|
|
10
11
|
struct JsArray
|
|
@@ -18,6 +19,7 @@ namespace jspp
|
|
|
18
19
|
explicit JsArray(const std::vector<std::optional<AnyValue>> &items) : dense(items), length(items.size()) {}
|
|
19
20
|
|
|
20
21
|
std::string to_std_string() const;
|
|
22
|
+
JsIterator<AnyValue> get_iterator();
|
|
21
23
|
|
|
22
24
|
AnyValue get_property(const std::string &key);
|
|
23
25
|
AnyValue get_property(uint32_t idx);
|
|
@@ -4,15 +4,47 @@
|
|
|
4
4
|
|
|
5
5
|
namespace jspp
|
|
6
6
|
{
|
|
7
|
+
// Forward declaration of AnyValue
|
|
7
8
|
class AnyValue;
|
|
8
9
|
|
|
10
|
+
using JsFunctionCallable = std::variant<std::function<AnyValue(const std::vector<AnyValue> &)>, // 0: Normal
|
|
11
|
+
std::function<jspp::JsIterator<jspp::AnyValue>(const std::vector<jspp::AnyValue> &)>>; // 1: Generator
|
|
12
|
+
|
|
9
13
|
struct JsFunction
|
|
10
14
|
{
|
|
11
|
-
|
|
15
|
+
JsFunctionCallable callable;
|
|
12
16
|
std::string name;
|
|
13
17
|
std::unordered_map<std::string, AnyValue> props;
|
|
18
|
+
bool is_generator;
|
|
19
|
+
|
|
20
|
+
// ---- Constructor A: infer is_generator using index() ----
|
|
21
|
+
JsFunction(const JsFunctionCallable &c,
|
|
22
|
+
std::string n = {},
|
|
23
|
+
std::unordered_map<std::string, AnyValue> p = {})
|
|
24
|
+
: callable(c),
|
|
25
|
+
name(std::move(n)),
|
|
26
|
+
props(std::move(p)),
|
|
27
|
+
is_generator(callable.index() == 1) // 1 = generator
|
|
28
|
+
{
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ---- Constructor B: explicitly set is_generator ----
|
|
32
|
+
JsFunction(const JsFunctionCallable &c,
|
|
33
|
+
bool is_gen,
|
|
34
|
+
std::string n = {},
|
|
35
|
+
std::unordered_map<std::string, AnyValue> p = {})
|
|
36
|
+
: callable(c),
|
|
37
|
+
name(std::move(n)),
|
|
38
|
+
props(std::move(p)),
|
|
39
|
+
is_generator(is_gen)
|
|
40
|
+
{
|
|
41
|
+
// Optional debug check (no RTTI, no variant visitation):
|
|
42
|
+
// if (callable.index() == 1 && !is_gen) { ... }
|
|
43
|
+
// if (callable.index() == 0 && is_gen) { ... }
|
|
44
|
+
}
|
|
14
45
|
|
|
15
46
|
std::string to_std_string() const;
|
|
47
|
+
AnyValue call(const std::vector<AnyValue> &args);
|
|
16
48
|
AnyValue get_property(const std::string &key);
|
|
17
49
|
AnyValue set_property(const std::string &key, const AnyValue &value);
|
|
18
50
|
};
|