@ugo-studio/jspp 0.3.2 → 0.3.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/dist/interpreter/core/codegen/expression-handlers.js +92 -21
- package/package.json +2 -2
- package/scripts/precompile-headers.ts +9 -1
- package/src/prelude/utils/access.hpp +0 -34
- package/src/prelude/utils/assignment_operators.hpp +96 -0
- package/src/prelude/utils/operators.hpp +36 -1
- package/src/prelude/utils/operators_native.hpp +12 -1
- package/src/prelude/values/iterator.cpp +262 -210
|
@@ -247,6 +247,17 @@ export function visitPrefixUnaryExpression(node, context) {
|
|
|
247
247
|
const operand = this.visit(prefixUnaryExpr.operand, context);
|
|
248
248
|
const operator = ts.tokenToString(prefixUnaryExpr.operator);
|
|
249
249
|
if (operator === "++" || operator === "--") {
|
|
250
|
+
const opFunc = operator === "++" ? "add" : "sub";
|
|
251
|
+
if (ts.isPropertyAccessExpression(prefixUnaryExpr.operand)) {
|
|
252
|
+
const obj = this.visit(prefixUnaryExpr.operand.expression, context);
|
|
253
|
+
const prop = visitObjectPropertyName.call(this, prefixUnaryExpr.operand.name, context);
|
|
254
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), 1.0))`;
|
|
255
|
+
}
|
|
256
|
+
else if (ts.isElementAccessExpression(prefixUnaryExpr.operand)) {
|
|
257
|
+
const obj = this.visit(prefixUnaryExpr.operand.expression, context);
|
|
258
|
+
const prop = visitObjectPropertyName.call(this, prefixUnaryExpr.operand.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
259
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), 1.0))`;
|
|
260
|
+
}
|
|
250
261
|
let target = operand;
|
|
251
262
|
if (ts.isIdentifier(prefixUnaryExpr.operand)) {
|
|
252
263
|
const scope = this.getScopeForNode(prefixUnaryExpr.operand);
|
|
@@ -289,6 +300,20 @@ export function visitPostfixUnaryExpression(node, context) {
|
|
|
289
300
|
const postfixUnaryExpr = node;
|
|
290
301
|
const operand = this.visit(postfixUnaryExpr.operand, context);
|
|
291
302
|
const operator = ts.tokenToString(postfixUnaryExpr.operator);
|
|
303
|
+
if (ts.isPropertyAccessExpression(postfixUnaryExpr.operand)) {
|
|
304
|
+
const obj = this.visit(postfixUnaryExpr.operand.expression, context);
|
|
305
|
+
const prop = visitObjectPropertyName.call(this, postfixUnaryExpr.operand.name, context);
|
|
306
|
+
const opFunc = operator === "++" ? "add" : "sub";
|
|
307
|
+
// Postfix needs IILE to return old value
|
|
308
|
+
return `([&]() { auto oldVal = ${obj}.get_own_property(${prop}); ${obj}.set_own_property(${prop}, jspp::${opFunc}(oldVal, 1.0)); return oldVal; })()`;
|
|
309
|
+
}
|
|
310
|
+
else if (ts.isElementAccessExpression(postfixUnaryExpr.operand)) {
|
|
311
|
+
const obj = this.visit(postfixUnaryExpr.operand.expression, context);
|
|
312
|
+
const prop = visitObjectPropertyName.call(this, postfixUnaryExpr.operand.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
313
|
+
const opFunc = operator === "++" ? "add" : "sub";
|
|
314
|
+
// Postfix needs IILE to return old value
|
|
315
|
+
return `([&]() { auto oldVal = ${obj}.get_own_property(${prop}); ${obj}.set_own_property(${prop}, jspp::${opFunc}(oldVal, 1.0)); return oldVal; })()`;
|
|
316
|
+
}
|
|
292
317
|
let target = operand;
|
|
293
318
|
if (ts.isIdentifier(postfixUnaryExpr.operand)) {
|
|
294
319
|
const scope = this.getScopeForNode(postfixUnaryExpr.operand);
|
|
@@ -402,42 +427,36 @@ export function visitBinaryExpression(node, context) {
|
|
|
402
427
|
if (assignmentOperators.includes(opToken.kind)) {
|
|
403
428
|
if (opToken.kind ===
|
|
404
429
|
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
|
|
405
|
-
const leftText = this.visit(binExpr.left, visitContext);
|
|
406
430
|
const rightText = this.visit(binExpr.right, visitContext);
|
|
407
|
-
let target = leftText;
|
|
408
431
|
if (ts.isIdentifier(binExpr.left)) {
|
|
432
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
409
433
|
const scope = this.getScopeForNode(binExpr.left);
|
|
410
434
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
411
|
-
target = typeInfo?.needsHeapAllocation
|
|
435
|
+
const target = typeInfo?.needsHeapAllocation
|
|
412
436
|
? `*${leftText}`
|
|
413
437
|
: leftText;
|
|
414
|
-
return
|
|
438
|
+
return `jspp::unsigned_right_shift_assign(${target}, ${rightText})`;
|
|
415
439
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (ts.
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
? `*${leftText}`
|
|
426
|
-
: leftText;
|
|
427
|
-
return `${target} = jspp::pow(${target}, ${rightText})`;
|
|
440
|
+
else if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
441
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
442
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.name, context);
|
|
443
|
+
return `${obj}.set_own_property(${prop}, jspp::unsigned_right_shift(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
444
|
+
}
|
|
445
|
+
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
446
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
447
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
448
|
+
return `${obj}.set_own_property(${prop}, jspp::unsigned_right_shift(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
428
449
|
}
|
|
429
|
-
// For complex LHS, we need a different approach, but this is a start.
|
|
430
450
|
}
|
|
431
451
|
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
432
452
|
opToken.kind === ts.SyntaxKind.BarBarEqualsToken ||
|
|
433
453
|
opToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
|
|
434
|
-
const leftText = this.visit(binExpr.left, visitContext);
|
|
435
454
|
const rightText = this.visit(binExpr.right, visitContext);
|
|
436
|
-
let target = leftText;
|
|
437
455
|
if (ts.isIdentifier(binExpr.left)) {
|
|
456
|
+
const leftText = this.visit(binExpr.left, visitContext);
|
|
438
457
|
const scope = this.getScopeForNode(binExpr.left);
|
|
439
458
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.left.text, scope);
|
|
440
|
-
target = typeInfo?.needsHeapAllocation
|
|
459
|
+
const target = typeInfo?.needsHeapAllocation
|
|
441
460
|
? `*${leftText}`
|
|
442
461
|
: leftText;
|
|
443
462
|
if (opToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
|
|
@@ -450,6 +469,29 @@ export function visitBinaryExpression(node, context) {
|
|
|
450
469
|
return `jspp::nullish_coalesce_assign(${target}, ${rightText})`;
|
|
451
470
|
}
|
|
452
471
|
}
|
|
472
|
+
else if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
473
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
474
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.name, context);
|
|
475
|
+
const func = opToken.kind ===
|
|
476
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken
|
|
477
|
+
? "logical_and"
|
|
478
|
+
: (opToken.kind === ts.SyntaxKind.BarBarEqualsToken
|
|
479
|
+
? "logical_or"
|
|
480
|
+
: "nullish_coalesce");
|
|
481
|
+
// Logical assignments return newVal, set_own_property returns newVal.
|
|
482
|
+
return `${obj}.set_own_property(${prop}, jspp::${func}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
483
|
+
}
|
|
484
|
+
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
485
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
486
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
487
|
+
const func = opToken.kind ===
|
|
488
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken
|
|
489
|
+
? "logical_and"
|
|
490
|
+
: (opToken.kind === ts.SyntaxKind.BarBarEqualsToken
|
|
491
|
+
? "logical_or"
|
|
492
|
+
: "nullish_coalesce");
|
|
493
|
+
return `${obj}.set_own_property(${prop}, jspp::${func}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
494
|
+
}
|
|
453
495
|
}
|
|
454
496
|
const leftText = this.visit(binExpr.left, visitContext);
|
|
455
497
|
let rightText = ts.isNumericLiteral(binExpr.right)
|
|
@@ -460,6 +502,35 @@ export function visitBinaryExpression(node, context) {
|
|
|
460
502
|
const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(binExpr.right.getText(), scope);
|
|
461
503
|
rightText = this.getDerefCode(rightText, this.getJsVarName(binExpr.right), visitContext, typeInfo);
|
|
462
504
|
}
|
|
505
|
+
if (ts.isPropertyAccessExpression(binExpr.left)) {
|
|
506
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
507
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.name, context);
|
|
508
|
+
const opBase = op.slice(0, -1); // "+=", "-=" -> "+", "-"
|
|
509
|
+
const opFunc = opBase === "+" ? "add" : (opBase === "-" ? "sub" : (opBase === "*" ? "mul" : (opBase === "/" ? "div" : (opBase === "%" ? "mod" : (opBase === "&" ? "bitwise_and" : (opBase === "|" ? "bitwise_or" : (opBase === "^" ? "bitwise_xor" : (opBase === "<<" ? "left_shift" : (opBase === ">>"
|
|
510
|
+
? "right_shift"
|
|
511
|
+
: "")))))))));
|
|
512
|
+
if (opFunc) {
|
|
513
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
// Fallback to IILE if we don't have an opFunc mapping
|
|
517
|
+
return `([&]() { auto val = ${obj}.get_own_property(${prop}); val ${op} ${rightText}; ${obj}.set_own_property(${prop}, val); return val; })()`;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
else if (ts.isElementAccessExpression(binExpr.left)) {
|
|
521
|
+
const obj = this.visit(binExpr.left.expression, context);
|
|
522
|
+
const prop = visitObjectPropertyName.call(this, binExpr.left.argumentExpression, { ...context, isBracketNotationPropertyAccess: true });
|
|
523
|
+
const opBase = op.slice(0, -1);
|
|
524
|
+
const opFunc = opBase === "+" ? "add" : (opBase === "-" ? "sub" : (opBase === "*" ? "mul" : (opBase === "/" ? "div" : (opBase === "%" ? "mod" : (opBase === "&" ? "bitwise_and" : (opBase === "|" ? "bitwise_or" : (opBase === "^" ? "bitwise_xor" : (opBase === "<<" ? "left_shift" : (opBase === ">>"
|
|
525
|
+
? "right_shift"
|
|
526
|
+
: "")))))))));
|
|
527
|
+
if (opFunc) {
|
|
528
|
+
return `${obj}.set_own_property(${prop}, jspp::${opFunc}(${obj}.get_own_property(${prop}), ${rightText}))`;
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
return `([&]() { auto val = ${obj}.get_own_property(${prop}); val ${op} ${rightText}; ${obj}.set_own_property(${prop}, val); return val; })()`;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
463
534
|
let target = leftText;
|
|
464
535
|
if (ts.isIdentifier(binExpr.left)) {
|
|
465
536
|
const scope = this.getScopeForNode(binExpr.left);
|
|
@@ -1266,7 +1337,7 @@ export function visitTypeOfExpression(node, context) {
|
|
|
1266
1337
|
derefExpr = this.getDerefCode(exprText, this.getJsVarName(typeOfExpr.expression), context, typeInfo);
|
|
1267
1338
|
}
|
|
1268
1339
|
}
|
|
1269
|
-
return `jspp::
|
|
1340
|
+
return `jspp::type_of(${derefExpr})`;
|
|
1270
1341
|
}
|
|
1271
1342
|
export function visitAwaitExpression(node, context) {
|
|
1272
1343
|
const awaitExpr = node;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ugo-studio/jspp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "A modern transpiler that converts JavaScript code into high-performance, standard C++23.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"scripts"
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
|
-
"postinstall": "bun run scripts/setup-compiler.ts && bun run scripts/setup-emsdk.ts && bun run scripts/precompile-headers.ts",
|
|
17
|
+
"postinstall": "bun run scripts/setup-compiler.ts && bun run scripts/setup-emsdk.ts && bun run scripts/precompile-headers.ts --mode debug",
|
|
18
18
|
"dev": "bun run src/cli/index.ts",
|
|
19
19
|
"typecheck": "tsc --noEmit",
|
|
20
20
|
"test": "bun test",
|
|
@@ -112,6 +112,14 @@ if (process.platform === "win32") {
|
|
|
112
112
|
MODES[1].flags.push("-Wa,-mbig-obj");
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
const pkgDir = path.dirname(import.meta.dirname);
|
|
116
|
+
const emsdkEnv = {
|
|
117
|
+
...process.env,
|
|
118
|
+
PATH: `${path.join(pkgDir, ".emsdk")}${path.delimiter}${
|
|
119
|
+
path.join(pkgDir, ".emsdk", "upstream", "emscripten")
|
|
120
|
+
}${path.delimiter}${process.env.PATH}`,
|
|
121
|
+
};
|
|
122
|
+
|
|
115
123
|
async function getLatestMtime(
|
|
116
124
|
dirPath: string,
|
|
117
125
|
filter?: (name: string) => boolean,
|
|
@@ -146,11 +154,11 @@ async function findCppFiles(dir: string): Promise<string[]> {
|
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
async function runCommand(cmd: string, args: string[]): Promise<boolean> {
|
|
149
|
-
// console.log(`${COLORS.dim}> ${cmd} ${args.join(" ")}${COLORS.reset}`);
|
|
150
157
|
return new Promise((resolve) => {
|
|
151
158
|
const proc = spawn(cmd, args, {
|
|
152
159
|
stdio: "inherit",
|
|
153
160
|
shell: process.platform === "win32",
|
|
161
|
+
env: emsdkEnv,
|
|
154
162
|
});
|
|
155
163
|
proc.on("close", (code) => resolve(code === 0));
|
|
156
164
|
});
|
|
@@ -48,40 +48,6 @@ namespace jspp
|
|
|
48
48
|
return var;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
inline AnyValue type_of(const std::optional<AnyValue> &val = std::nullopt)
|
|
52
|
-
{
|
|
53
|
-
if (!val.has_value())
|
|
54
|
-
return AnyValue::make_string("undefined");
|
|
55
|
-
|
|
56
|
-
switch (val.value().get_type())
|
|
57
|
-
{
|
|
58
|
-
case JsType::Undefined:
|
|
59
|
-
return AnyValue::make_string("undefined");
|
|
60
|
-
case JsType::Null:
|
|
61
|
-
return AnyValue::make_string("object");
|
|
62
|
-
case JsType::Boolean:
|
|
63
|
-
return AnyValue::make_string("boolean");
|
|
64
|
-
case JsType::Number:
|
|
65
|
-
return AnyValue::make_string("number");
|
|
66
|
-
case JsType::String:
|
|
67
|
-
return AnyValue::make_string("string");
|
|
68
|
-
case JsType::Symbol:
|
|
69
|
-
return AnyValue::make_string("symbol");
|
|
70
|
-
case JsType::Function:
|
|
71
|
-
return AnyValue::make_string("function");
|
|
72
|
-
case JsType::Object:
|
|
73
|
-
return AnyValue::make_string("object");
|
|
74
|
-
case JsType::Array:
|
|
75
|
-
return AnyValue::make_string("object");
|
|
76
|
-
case JsType::Iterator:
|
|
77
|
-
return AnyValue::make_string("object");
|
|
78
|
-
case JsType::AsyncIterator:
|
|
79
|
-
return AnyValue::make_string("object");
|
|
80
|
-
default:
|
|
81
|
-
return AnyValue::make_string("undefined");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
51
|
// Helper function to get enumerable own property keys/values of an object
|
|
86
52
|
inline std::vector<AnyValue> get_object_keys(const AnyValue &obj, bool include_symbols = false)
|
|
87
53
|
{
|
|
@@ -39,6 +39,42 @@ namespace jspp
|
|
|
39
39
|
return lhs;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
inline AnyValue &operator&=(AnyValue &lhs, const AnyValue &rhs)
|
|
43
|
+
{
|
|
44
|
+
lhs = jspp::bitwise_and(lhs, rhs);
|
|
45
|
+
return lhs;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
inline AnyValue &operator|=(AnyValue &lhs, const AnyValue &rhs)
|
|
49
|
+
{
|
|
50
|
+
lhs = jspp::bitwise_or(lhs, rhs);
|
|
51
|
+
return lhs;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
inline AnyValue &operator^=(AnyValue &lhs, const AnyValue &rhs)
|
|
55
|
+
{
|
|
56
|
+
lhs = jspp::bitwise_xor(lhs, rhs);
|
|
57
|
+
return lhs;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
inline AnyValue &operator<<=(AnyValue &lhs, const AnyValue &rhs)
|
|
61
|
+
{
|
|
62
|
+
lhs = jspp::left_shift(lhs, rhs);
|
|
63
|
+
return lhs;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
inline AnyValue &operator>>=(AnyValue &lhs, const AnyValue &rhs)
|
|
67
|
+
{
|
|
68
|
+
lhs = jspp::right_shift(lhs, rhs);
|
|
69
|
+
return lhs;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
inline AnyValue &unsigned_right_shift_assign(AnyValue &lhs, const AnyValue &rhs)
|
|
73
|
+
{
|
|
74
|
+
lhs = jspp::unsigned_right_shift(lhs, rhs);
|
|
75
|
+
return lhs;
|
|
76
|
+
}
|
|
77
|
+
|
|
42
78
|
inline AnyValue &operator++(AnyValue &val)
|
|
43
79
|
{
|
|
44
80
|
val = jspp::add(val, 1.0);
|
|
@@ -116,4 +152,64 @@ namespace jspp
|
|
|
116
152
|
{
|
|
117
153
|
return lhs %= static_cast<double>(rhs);
|
|
118
154
|
}
|
|
155
|
+
|
|
156
|
+
inline AnyValue &operator&=(AnyValue &lhs, const double &rhs)
|
|
157
|
+
{
|
|
158
|
+
lhs = jspp::bitwise_and(lhs, rhs);
|
|
159
|
+
return lhs;
|
|
160
|
+
}
|
|
161
|
+
inline AnyValue &operator&=(AnyValue &lhs, const int &rhs)
|
|
162
|
+
{
|
|
163
|
+
return lhs &= static_cast<double>(rhs);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
inline AnyValue &operator|=(AnyValue &lhs, const double &rhs)
|
|
167
|
+
{
|
|
168
|
+
lhs = jspp::bitwise_or(lhs, rhs);
|
|
169
|
+
return lhs;
|
|
170
|
+
}
|
|
171
|
+
inline AnyValue &operator|=(AnyValue &lhs, const int &rhs)
|
|
172
|
+
{
|
|
173
|
+
return lhs |= static_cast<double>(rhs);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
inline AnyValue &operator^=(AnyValue &lhs, const double &rhs)
|
|
177
|
+
{
|
|
178
|
+
lhs = jspp::bitwise_xor(lhs, rhs);
|
|
179
|
+
return lhs;
|
|
180
|
+
}
|
|
181
|
+
inline AnyValue &operator^=(AnyValue &lhs, const int &rhs)
|
|
182
|
+
{
|
|
183
|
+
return lhs ^= static_cast<double>(rhs);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
inline AnyValue &operator<<=(AnyValue &lhs, const double &rhs)
|
|
187
|
+
{
|
|
188
|
+
lhs = jspp::left_shift(lhs, rhs);
|
|
189
|
+
return lhs;
|
|
190
|
+
}
|
|
191
|
+
inline AnyValue &operator<<=(AnyValue &lhs, const int &rhs)
|
|
192
|
+
{
|
|
193
|
+
return lhs <<= static_cast<double>(rhs);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
inline AnyValue &operator>>=(AnyValue &lhs, const double &rhs)
|
|
197
|
+
{
|
|
198
|
+
lhs = jspp::right_shift(lhs, rhs);
|
|
199
|
+
return lhs;
|
|
200
|
+
}
|
|
201
|
+
inline AnyValue &operator>>=(AnyValue &lhs, const int &rhs)
|
|
202
|
+
{
|
|
203
|
+
return lhs >>= static_cast<double>(rhs);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
inline AnyValue &unsigned_right_shift_assign(AnyValue &lhs, const double &rhs)
|
|
207
|
+
{
|
|
208
|
+
lhs = jspp::unsigned_right_shift(lhs, rhs);
|
|
209
|
+
return lhs;
|
|
210
|
+
}
|
|
211
|
+
inline AnyValue &unsigned_right_shift_assign(AnyValue &lhs, const int &rhs)
|
|
212
|
+
{
|
|
213
|
+
return unsigned_right_shift_assign(lhs, static_cast<double>(rhs));
|
|
214
|
+
}
|
|
119
215
|
}
|
|
@@ -11,6 +11,41 @@
|
|
|
11
11
|
|
|
12
12
|
namespace jspp
|
|
13
13
|
{
|
|
14
|
+
// --- TYPE OF ---
|
|
15
|
+
inline AnyValue type_of(const std::optional<AnyValue> &val = std::nullopt)
|
|
16
|
+
{
|
|
17
|
+
if (!val.has_value())
|
|
18
|
+
return AnyValue::make_string("undefined");
|
|
19
|
+
|
|
20
|
+
switch (val.value().get_type())
|
|
21
|
+
{
|
|
22
|
+
case JsType::Undefined:
|
|
23
|
+
return AnyValue::make_string("undefined");
|
|
24
|
+
case JsType::Null:
|
|
25
|
+
return AnyValue::make_string("object");
|
|
26
|
+
case JsType::Boolean:
|
|
27
|
+
return AnyValue::make_string("boolean");
|
|
28
|
+
case JsType::Number:
|
|
29
|
+
return AnyValue::make_string("number");
|
|
30
|
+
case JsType::String:
|
|
31
|
+
return AnyValue::make_string("string");
|
|
32
|
+
case JsType::Symbol:
|
|
33
|
+
return AnyValue::make_string("symbol");
|
|
34
|
+
case JsType::Function:
|
|
35
|
+
return AnyValue::make_string("function");
|
|
36
|
+
case JsType::Object:
|
|
37
|
+
return AnyValue::make_string("object");
|
|
38
|
+
case JsType::Array:
|
|
39
|
+
return AnyValue::make_string("object");
|
|
40
|
+
case JsType::Iterator:
|
|
41
|
+
return AnyValue::make_string("object");
|
|
42
|
+
case JsType::AsyncIterator:
|
|
43
|
+
return AnyValue::make_string("object");
|
|
44
|
+
default:
|
|
45
|
+
return AnyValue::make_string("undefined");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
14
49
|
// Operator === (returns boolean wrapped in AnyValue)
|
|
15
50
|
inline const AnyValue is_strictly_equal_to(const AnyValue &lhs, const double &rhs) noexcept
|
|
16
51
|
{
|
|
@@ -349,4 +384,4 @@ namespace jspp
|
|
|
349
384
|
return lhs;
|
|
350
385
|
return rhs;
|
|
351
386
|
}
|
|
352
|
-
}
|
|
387
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
4
|
#include "any_value.hpp"
|
|
5
|
+
#include "exception.hpp"
|
|
5
6
|
#include <cstdint> // For int32_t
|
|
6
7
|
#include <cmath> // For fmod, isnan, isinf, floor, abs, pow
|
|
7
8
|
#include <string> // For std::to_string, std::stod
|
|
@@ -109,6 +110,16 @@ namespace jspp
|
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
// --- UNARY NATIVE ---
|
|
114
|
+
inline double plus_native(const AnyValue &val) { return Operators_Private::ToNumber(val); }
|
|
115
|
+
inline double plus_native(double val) { return val; }
|
|
116
|
+
inline double negate_native(const AnyValue &val) { return -Operators_Private::ToNumber(val); }
|
|
117
|
+
inline double negate_native(double val) { return -val; }
|
|
118
|
+
inline double bitwise_not_native(const AnyValue &val) { return static_cast<double>(~Operators_Private::ToInt32(val)); }
|
|
119
|
+
inline double bitwise_not_native(double val) { return static_cast<double>(~static_cast<int32_t>(val)); }
|
|
120
|
+
inline bool logical_not_native(const AnyValue &val) { return !is_truthy(val); }
|
|
121
|
+
inline bool logical_not_native(double val) { return !is_truthy(val); }
|
|
122
|
+
|
|
112
123
|
// --- BASIC EQUALITY ---
|
|
113
124
|
|
|
114
125
|
// Operator === (returns primitive boolean)
|
|
@@ -346,4 +357,4 @@ namespace jspp
|
|
|
346
357
|
inline double unsigned_right_shift_native(const AnyValue &lhs, const double &rhs) { return unsigned_right_shift_native(Operators_Private::ToUint32(lhs), rhs); }
|
|
347
358
|
inline double unsigned_right_shift_native(const double &lhs, const AnyValue &rhs) { return unsigned_right_shift_native(lhs, Operators_Private::ToInt32(rhs)); }
|
|
348
359
|
|
|
349
|
-
}
|
|
360
|
+
}
|
|
@@ -2,210 +2,251 @@
|
|
|
2
2
|
#include "values/iterator.hpp"
|
|
3
3
|
#include "values/prototypes/iterator.hpp"
|
|
4
4
|
|
|
5
|
-
namespace jspp
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
template <typename T>
|
|
25
|
-
std::suspend_always JsIterator<T>::promise_type::initial_suspend() noexcept { return {}; }
|
|
26
|
-
|
|
27
|
-
template <typename T>
|
|
28
|
-
std::suspend_always JsIterator<T>::promise_type::final_suspend() noexcept { return {}; }
|
|
29
|
-
|
|
30
|
-
template <typename T>
|
|
31
|
-
void JsIterator<T>::promise_type::unhandled_exception() {
|
|
32
|
-
try {
|
|
33
|
-
throw;
|
|
34
|
-
} catch (const GeneratorReturnException&) {
|
|
35
|
-
} catch (...) {
|
|
36
|
-
exception_ = std::current_exception();
|
|
5
|
+
namespace jspp
|
|
6
|
+
{
|
|
7
|
+
|
|
8
|
+
template <typename T>
|
|
9
|
+
JsIterator<T>::JsIterator(handle_type h) : handle(h) {}
|
|
10
|
+
|
|
11
|
+
template <typename T>
|
|
12
|
+
JsIterator<T>::JsIterator(JsIterator &&other) noexcept
|
|
13
|
+
: handle(std::exchange(other.handle, nullptr)),
|
|
14
|
+
props(std::move(other.props)),
|
|
15
|
+
symbol_props(std::move(other.symbol_props)) {}
|
|
16
|
+
|
|
17
|
+
template <typename T>
|
|
18
|
+
JsIterator<T>::~JsIterator()
|
|
19
|
+
{
|
|
20
|
+
if (handle)
|
|
21
|
+
handle.destroy();
|
|
37
22
|
}
|
|
38
|
-
}
|
|
39
23
|
|
|
40
|
-
template <typename T>
|
|
41
|
-
|
|
24
|
+
template <typename T>
|
|
25
|
+
JsIterator<T> JsIterator<T>::promise_type::get_return_object()
|
|
26
|
+
{
|
|
27
|
+
return JsIterator{std::coroutine_handle<promise_type>::from_promise(*this)};
|
|
28
|
+
}
|
|
42
29
|
|
|
43
|
-
template <typename T>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
template <typename T>
|
|
66
|
-
typename JsIterator<T>::NextResult JsIterator<T>::throw_(const AnyValue &err)
|
|
67
|
-
{
|
|
68
|
-
if (!handle || handle.done()) throw Exception(err);
|
|
69
|
-
handle.promise().pending_exception = std::make_exception_ptr(Exception(err));
|
|
70
|
-
handle.resume();
|
|
71
|
-
if (handle.promise().exception_) std::rethrow_exception(handle.promise().exception_);
|
|
72
|
-
bool is_done = handle.done();
|
|
73
|
-
return {handle.promise().current_value, is_done};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
template <typename T>
|
|
77
|
-
std::vector<T> JsIterator<T>::to_vector()
|
|
78
|
-
{
|
|
79
|
-
std::vector<T> result;
|
|
80
|
-
while (true) {
|
|
81
|
-
auto next_res = this->next();
|
|
82
|
-
if (next_res.done) break;
|
|
83
|
-
result.push_back(next_res.value.value_or(Constants::UNDEFINED));
|
|
30
|
+
template <typename T>
|
|
31
|
+
std::suspend_always JsIterator<T>::promise_type::initial_suspend() noexcept { return {}; }
|
|
32
|
+
|
|
33
|
+
template <typename T>
|
|
34
|
+
std::suspend_always JsIterator<T>::promise_type::final_suspend() noexcept { return {}; }
|
|
35
|
+
|
|
36
|
+
template <typename T>
|
|
37
|
+
void JsIterator<T>::promise_type::unhandled_exception()
|
|
38
|
+
{
|
|
39
|
+
try
|
|
40
|
+
{
|
|
41
|
+
throw;
|
|
42
|
+
}
|
|
43
|
+
catch (const GeneratorReturnException &)
|
|
44
|
+
{
|
|
45
|
+
}
|
|
46
|
+
catch (...)
|
|
47
|
+
{
|
|
48
|
+
exception_ = std::current_exception();
|
|
49
|
+
}
|
|
84
50
|
}
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
51
|
|
|
88
|
-
template <typename T>
|
|
89
|
-
|
|
52
|
+
template <typename T>
|
|
53
|
+
std::string JsIterator<T>::to_std_string() const { return "[object Generator]"; }
|
|
54
|
+
|
|
55
|
+
template <typename T>
|
|
56
|
+
typename JsIterator<T>::NextResult JsIterator<T>::next(const T &val)
|
|
57
|
+
{
|
|
58
|
+
if (!handle || handle.done())
|
|
59
|
+
return {std::nullopt, true};
|
|
60
|
+
handle.promise().input_value = val;
|
|
61
|
+
handle.resume();
|
|
62
|
+
if (handle.promise().exception_)
|
|
63
|
+
std::rethrow_exception(handle.promise().exception_);
|
|
64
|
+
bool is_done = handle.done();
|
|
65
|
+
return {handle.promise().current_value, is_done};
|
|
66
|
+
}
|
|
90
67
|
|
|
91
|
-
template <typename T>
|
|
92
|
-
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
68
|
+
template <typename T>
|
|
69
|
+
typename JsIterator<T>::NextResult JsIterator<T>::return_(const T &val)
|
|
70
|
+
{
|
|
71
|
+
if (!handle || handle.done())
|
|
72
|
+
return {val, true};
|
|
73
|
+
handle.promise().pending_return = true;
|
|
74
|
+
handle.promise().current_value = val;
|
|
75
|
+
handle.resume();
|
|
76
|
+
if (handle.promise().exception_)
|
|
77
|
+
std::rethrow_exception(handle.promise().exception_);
|
|
78
|
+
return {handle.promise().current_value, true};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
template <typename T>
|
|
82
|
+
typename JsIterator<T>::NextResult JsIterator<T>::throw_(const AnyValue &err)
|
|
83
|
+
{
|
|
84
|
+
if (!handle || handle.done())
|
|
85
|
+
throw Exception(err);
|
|
86
|
+
handle.promise().pending_exception = std::make_exception_ptr(Exception(err));
|
|
87
|
+
handle.resume();
|
|
88
|
+
if (handle.promise().exception_)
|
|
89
|
+
std::rethrow_exception(handle.promise().exception_);
|
|
90
|
+
bool is_done = handle.done();
|
|
91
|
+
return {handle.promise().current_value, is_done};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
template <typename T>
|
|
95
|
+
std::vector<T> JsIterator<T>::to_vector()
|
|
96
|
+
{
|
|
97
|
+
std::vector<T> result;
|
|
98
|
+
while (true)
|
|
99
|
+
{
|
|
100
|
+
auto next_res = this->next();
|
|
101
|
+
if (next_res.done)
|
|
102
|
+
break;
|
|
103
|
+
result.push_back(next_res.value.value_or(Constants::UNDEFINED));
|
|
99
104
|
}
|
|
100
|
-
return
|
|
105
|
+
return result;
|
|
101
106
|
}
|
|
102
|
-
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
103
|
-
}
|
|
104
107
|
|
|
105
|
-
template <typename T>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
template <typename T>
|
|
109
|
+
bool JsIterator<T>::has_symbol_property(const AnyValue &key) const { return symbol_props.count(key) > 0; }
|
|
110
|
+
|
|
111
|
+
template <typename T>
|
|
112
|
+
AnyValue JsIterator<T>::get_property(const std::string &key, AnyValue thisVal)
|
|
113
|
+
{
|
|
114
|
+
auto it = props.find(key);
|
|
115
|
+
if (it == props.end())
|
|
116
|
+
{
|
|
117
|
+
if constexpr (std::is_same_v<T, AnyValue>)
|
|
118
|
+
{
|
|
119
|
+
auto proto_it = IteratorPrototypes::get(key);
|
|
120
|
+
if (proto_it.has_value())
|
|
121
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
122
|
+
}
|
|
123
|
+
return Constants::UNDEFINED;
|
|
113
124
|
}
|
|
114
|
-
return
|
|
125
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
115
126
|
}
|
|
116
|
-
return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
|
|
117
|
-
}
|
|
118
127
|
|
|
119
|
-
template <typename T>
|
|
120
|
-
AnyValue JsIterator<T>::
|
|
121
|
-
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
template <typename T>
|
|
129
|
+
AnyValue JsIterator<T>::get_symbol_property(const AnyValue &key, AnyValue thisVal)
|
|
130
|
+
{
|
|
131
|
+
auto it = symbol_props.find(key);
|
|
132
|
+
if (it == symbol_props.end())
|
|
133
|
+
{
|
|
134
|
+
if constexpr (std::is_same_v<T, AnyValue>)
|
|
135
|
+
{
|
|
136
|
+
auto proto_it = IteratorPrototypes::get(key);
|
|
137
|
+
if (proto_it.has_value())
|
|
138
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key.to_std_string());
|
|
139
|
+
}
|
|
140
|
+
return Constants::UNDEFINED;
|
|
128
141
|
}
|
|
142
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
|
|
129
143
|
}
|
|
130
|
-
auto it = props.find(key);
|
|
131
|
-
if (it != props.end()) return jspp::AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
132
|
-
else { props[key] = value; return value; }
|
|
133
|
-
}
|
|
134
144
|
|
|
135
|
-
template <typename T>
|
|
136
|
-
AnyValue JsIterator<T>::
|
|
137
|
-
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
template <typename T>
|
|
146
|
+
AnyValue JsIterator<T>::set_property(const std::string &key, AnyValue value, AnyValue thisVal)
|
|
147
|
+
{
|
|
148
|
+
if constexpr (std::is_same_v<T, AnyValue>)
|
|
149
|
+
{
|
|
150
|
+
auto proto_it = IteratorPrototypes::get(key);
|
|
151
|
+
if (proto_it.has_value())
|
|
152
|
+
{
|
|
153
|
+
auto proto_value = proto_it.value();
|
|
154
|
+
if (proto_value.is_accessor_descriptor())
|
|
155
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
156
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
157
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
auto it = props.find(key);
|
|
161
|
+
if (it != props.end())
|
|
162
|
+
return jspp::AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
163
|
+
else
|
|
164
|
+
{
|
|
165
|
+
props[key] = value;
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
142
169
|
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
template <typename T>
|
|
171
|
+
AnyValue JsIterator<T>::set_symbol_property(const AnyValue &key, AnyValue value, AnyValue thisVal)
|
|
172
|
+
{
|
|
173
|
+
auto it = symbol_props.find(key);
|
|
174
|
+
if (it != symbol_props.end())
|
|
175
|
+
return AnyValue::resolve_property_for_write(it->second, thisVal, value, key.to_std_string());
|
|
176
|
+
else
|
|
177
|
+
{
|
|
178
|
+
symbol_props[key] = value;
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
145
182
|
|
|
146
|
-
|
|
183
|
+
// Explicit template instantiation
|
|
184
|
+
template class JsIterator<AnyValue>;
|
|
147
185
|
|
|
148
|
-
|
|
149
|
-
{
|
|
150
|
-
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
151
|
-
{ return AnyValue::make_string(thisVal.as_iterator()->to_std_string()); },
|
|
152
|
-
"toString");
|
|
153
|
-
return fn;
|
|
154
|
-
}
|
|
186
|
+
namespace IteratorPrototypes
|
|
187
|
+
{
|
|
155
188
|
|
|
156
|
-
AnyValue &
|
|
157
|
-
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
189
|
+
AnyValue &get_toString_fn()
|
|
190
|
+
{
|
|
191
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
192
|
+
{ return AnyValue::make_string(thisVal.as_iterator()->to_std_string()); },
|
|
193
|
+
"toString");
|
|
194
|
+
return fn;
|
|
195
|
+
}
|
|
163
196
|
|
|
164
|
-
AnyValue &
|
|
165
|
-
{
|
|
166
|
-
|
|
167
|
-
|
|
197
|
+
AnyValue &get_iterator_fn()
|
|
198
|
+
{
|
|
199
|
+
static AnyValue fn = AnyValue::make_generator([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
200
|
+
{ return thisVal; },
|
|
201
|
+
"Symbol.iterator");
|
|
202
|
+
return fn;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
AnyValue &get_next_fn()
|
|
206
|
+
{
|
|
207
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
208
|
+
{
|
|
168
209
|
AnyValue val = args.empty() ? Constants::UNDEFINED : args[0];
|
|
169
210
|
auto res = thisVal.as_iterator()->next(val);
|
|
170
211
|
return AnyValue::make_object({{"value", res.value.value_or(Constants::UNDEFINED)}, {"done", AnyValue::make_boolean(res.done)}}); },
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
212
|
+
"next");
|
|
213
|
+
return fn;
|
|
214
|
+
}
|
|
174
215
|
|
|
175
|
-
AnyValue &get_return_fn()
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
216
|
+
AnyValue &get_return_fn()
|
|
217
|
+
{
|
|
218
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
219
|
+
{
|
|
179
220
|
AnyValue val = args.empty() ? Constants::UNDEFINED : args[0];
|
|
180
221
|
auto res = thisVal.as_iterator()->return_(val);
|
|
181
222
|
return AnyValue::make_object({{"value", res.value.value_or(Constants::UNDEFINED)}, {"done", AnyValue::make_boolean(res.done)}}); },
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
223
|
+
"return");
|
|
224
|
+
return fn;
|
|
225
|
+
}
|
|
185
226
|
|
|
186
|
-
AnyValue &get_throw_fn()
|
|
187
|
-
{
|
|
188
|
-
|
|
189
|
-
|
|
227
|
+
AnyValue &get_throw_fn()
|
|
228
|
+
{
|
|
229
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
230
|
+
{
|
|
190
231
|
AnyValue err = args.empty() ? Constants::UNDEFINED : args[0];
|
|
191
232
|
auto res = thisVal.as_iterator()->throw_(err);
|
|
192
233
|
return AnyValue::make_object({{"value", res.value.value_or(Constants::UNDEFINED)}, {"done", AnyValue::make_boolean(res.done)}}); },
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
234
|
+
"throw");
|
|
235
|
+
return fn;
|
|
236
|
+
}
|
|
196
237
|
|
|
197
|
-
AnyValue &get_toArray_fn()
|
|
198
|
-
{
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
238
|
+
AnyValue &get_toArray_fn()
|
|
239
|
+
{
|
|
240
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
241
|
+
{ return AnyValue::make_array(thisVal.as_iterator()->to_vector()); },
|
|
242
|
+
"toArray");
|
|
243
|
+
return fn;
|
|
244
|
+
}
|
|
204
245
|
|
|
205
|
-
AnyValue &get_drop_fn()
|
|
206
|
-
{
|
|
207
|
-
|
|
208
|
-
|
|
246
|
+
AnyValue &get_drop_fn()
|
|
247
|
+
{
|
|
248
|
+
static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> args) -> JsIterator<AnyValue>
|
|
249
|
+
{
|
|
209
250
|
auto self = thisVal.as_iterator();
|
|
210
251
|
size_t skip_count = 0;
|
|
211
252
|
if (!args.empty()) {
|
|
@@ -224,14 +265,14 @@ AnyValue &get_drop_fn()
|
|
|
224
265
|
co_yield next_res.value.value_or(Constants::UNDEFINED);
|
|
225
266
|
}
|
|
226
267
|
co_return jspp::Constants::UNDEFINED; },
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
268
|
+
"drop");
|
|
269
|
+
return fn;
|
|
270
|
+
}
|
|
230
271
|
|
|
231
|
-
AnyValue &get_take_fn()
|
|
232
|
-
{
|
|
233
|
-
|
|
234
|
-
|
|
272
|
+
AnyValue &get_take_fn()
|
|
273
|
+
{
|
|
274
|
+
static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> args) -> JsIterator<AnyValue>
|
|
275
|
+
{
|
|
235
276
|
auto self = thisVal.as_iterator();
|
|
236
277
|
size_t take_count = 0;
|
|
237
278
|
if (!args.empty()) {
|
|
@@ -254,14 +295,14 @@ AnyValue &get_take_fn()
|
|
|
254
295
|
}
|
|
255
296
|
}
|
|
256
297
|
co_return jspp::Constants::UNDEFINED; },
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
298
|
+
"take");
|
|
299
|
+
return fn;
|
|
300
|
+
}
|
|
260
301
|
|
|
261
|
-
AnyValue &get_some_fn()
|
|
262
|
-
{
|
|
263
|
-
|
|
264
|
-
|
|
302
|
+
AnyValue &get_some_fn()
|
|
303
|
+
{
|
|
304
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
305
|
+
{
|
|
265
306
|
auto self = thisVal.as_iterator();
|
|
266
307
|
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
267
308
|
auto callback = args[0].as_function();
|
|
@@ -269,7 +310,8 @@ AnyValue &get_some_fn()
|
|
|
269
310
|
{
|
|
270
311
|
auto next_res = self->next();
|
|
271
312
|
if (next_res.done) { break; }
|
|
272
|
-
|
|
313
|
+
AnyValue cb_arg = next_res.value.value_or(Constants::UNDEFINED);
|
|
314
|
+
if (is_truthy(callback->call(thisVal, std::span<const AnyValue>(&cb_arg, 1))))
|
|
273
315
|
{
|
|
274
316
|
self->return_();
|
|
275
317
|
return Constants::TRUE;
|
|
@@ -277,33 +319,43 @@ AnyValue &get_some_fn()
|
|
|
277
319
|
}
|
|
278
320
|
return jspp::Constants::FALSE; },
|
|
279
321
|
"some");
|
|
280
|
-
|
|
281
|
-
}
|
|
322
|
+
return fn;
|
|
323
|
+
}
|
|
282
324
|
|
|
283
|
-
std::optional<AnyValue> get(const std::string &key)
|
|
284
|
-
{
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
325
|
+
std::optional<AnyValue> get(const std::string &key)
|
|
326
|
+
{
|
|
327
|
+
if (key == "toString")
|
|
328
|
+
return get_toString_fn();
|
|
329
|
+
if (key == "next")
|
|
330
|
+
return get_next_fn();
|
|
331
|
+
if (key == "return")
|
|
332
|
+
return get_return_fn();
|
|
333
|
+
if (key == "throw")
|
|
334
|
+
return get_throw_fn();
|
|
335
|
+
if (key == "toArray")
|
|
336
|
+
return get_toArray_fn();
|
|
337
|
+
if (key == "drop")
|
|
338
|
+
return get_drop_fn();
|
|
339
|
+
if (key == "take")
|
|
340
|
+
return get_take_fn();
|
|
341
|
+
if (key == "some")
|
|
342
|
+
return get_some_fn();
|
|
343
|
+
return std::nullopt;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
std::optional<AnyValue> get(const AnyValue &key)
|
|
347
|
+
{
|
|
348
|
+
if (key.is_string())
|
|
349
|
+
return get(key.as_string()->value);
|
|
300
350
|
|
|
301
|
-
|
|
302
|
-
|
|
351
|
+
if (key == AnyValue::from_symbol(WellKnownSymbols::toStringTag))
|
|
352
|
+
return get_toString_fn();
|
|
353
|
+
if (key == AnyValue::from_symbol(WellKnownSymbols::iterator))
|
|
354
|
+
return get_iterator_fn();
|
|
303
355
|
|
|
304
|
-
|
|
305
|
-
}
|
|
356
|
+
return std::nullopt;
|
|
357
|
+
}
|
|
306
358
|
|
|
307
|
-
} // namespace IteratorPrototypes
|
|
359
|
+
} // namespace IteratorPrototypes
|
|
308
360
|
|
|
309
361
|
} // namespace jspp
|