porffor 0.56.6 → 0.56.8
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/compiler/2c.js +4 -1
- package/compiler/builtins/symbol.ts +19 -4
- package/compiler/builtins_precompiled.js +340 -343
- package/compiler/codegen.js +6 -0
- package/optional-chaining-tests.js +335 -0
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -351,6 +351,10 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
351
351
|
case 'TSAsExpression':
|
352
352
|
return cacheAst(decl, generate(scope, decl.expression));
|
353
353
|
|
354
|
+
case 'WithStatement':
|
355
|
+
if (Prefs.d) log.warning('codegen', 'with is not supported, treating as expression');
|
356
|
+
return cacheAst(decl, generate(scope, decl.body));
|
357
|
+
|
354
358
|
default:
|
355
359
|
// ignore typescript nodes
|
356
360
|
if (decl.type.startsWith('TS') ||
|
@@ -3196,6 +3200,7 @@ const setDefaultFuncName = (decl, name) => {
|
|
3196
3200
|
const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
3197
3201
|
// statically analyzed ffi dlopen hack to let 2c handle it
|
3198
3202
|
if (init && init.type === 'CallExpression' && init.callee.name === '__Porffor_dlopen') {
|
3203
|
+
if (Prefs.secure) throw new Error('Porffor.dlopen is not allowed in --secure');
|
3199
3204
|
if (Prefs.target !== 'native' && Prefs.target !== 'c' && !Prefs.native) throw new Error('Porffor.dlopen is only supported for native target (use --native)');
|
3200
3205
|
|
3201
3206
|
// disable pgo if using ffi (lol)
|
@@ -6404,6 +6409,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
|
|
6404
6409
|
},
|
6405
6410
|
|
6406
6411
|
__Porffor_c: str => {
|
6412
|
+
if (Prefs.secure) throw new Error('Porffor.c is not allowed in --secure');
|
6407
6413
|
return [
|
6408
6414
|
[ null, 'c', str ]
|
6409
6415
|
];
|
@@ -0,0 +1,335 @@
|
|
1
|
+
// Optional Chaining Tests
|
2
|
+
// This file tests all major features of the optional chaining operator (?.)
|
3
|
+
|
4
|
+
// Test utility function
|
5
|
+
function assert(condition, message) {
|
6
|
+
if (!condition) {
|
7
|
+
throw new Error('Assertion failed: ' + message);
|
8
|
+
}
|
9
|
+
return true;
|
10
|
+
}
|
11
|
+
|
12
|
+
// BASIC OBJECT PROPERTY ACCESS TESTS
|
13
|
+
console.log('\n=== Basic Object Property Access ===');
|
14
|
+
|
15
|
+
// Test 1: Basic property access with existing property
|
16
|
+
(function() {
|
17
|
+
const obj = { a: 1 };
|
18
|
+
assert(obj?.a === 1, 'Basic property access failed');
|
19
|
+
console.log('✓ Basic property access with existing property');
|
20
|
+
})();
|
21
|
+
|
22
|
+
// Test 2: Basic property access with undefined object
|
23
|
+
(function() {
|
24
|
+
const obj = undefined;
|
25
|
+
assert(obj?.a === undefined, 'Optional chaining with undefined object failed');
|
26
|
+
console.log('✓ Basic property access with undefined object');
|
27
|
+
})();
|
28
|
+
|
29
|
+
// Test 3: Basic property access with null object
|
30
|
+
(function() {
|
31
|
+
const obj = null;
|
32
|
+
assert(obj?.a === undefined, 'Optional chaining with null object failed');
|
33
|
+
console.log('✓ Basic property access with null object');
|
34
|
+
})();
|
35
|
+
|
36
|
+
// NESTED PROPERTY ACCESS TESTS
|
37
|
+
console.log('\n=== Nested Property Access ===');
|
38
|
+
|
39
|
+
// Test 4: Nested property access with all properties existing
|
40
|
+
(function() {
|
41
|
+
const obj = { a: { b: { c: 42 } } };
|
42
|
+
assert(obj?.a?.b?.c === 42, 'Nested property access failed');
|
43
|
+
console.log('✓ Nested property access with all properties existing');
|
44
|
+
})();
|
45
|
+
|
46
|
+
// Test 5: Nested property access with missing intermediate property
|
47
|
+
(function() {
|
48
|
+
const obj = { a: {} };
|
49
|
+
assert(obj?.a?.b?.c === undefined, 'Nested property access with missing intermediate property failed');
|
50
|
+
console.log('✓ Nested property access with missing intermediate property');
|
51
|
+
})();
|
52
|
+
|
53
|
+
// Test 6: Nested property access with null intermediate property
|
54
|
+
(function() {
|
55
|
+
const obj = { a: { b: null } };
|
56
|
+
assert(obj?.a?.b?.c === undefined, 'Nested property access with null intermediate property failed');
|
57
|
+
console.log('✓ Nested property access with null intermediate property');
|
58
|
+
})();
|
59
|
+
|
60
|
+
// METHOD CALL TESTS
|
61
|
+
console.log('\n=== Method Call Tests ===');
|
62
|
+
|
63
|
+
// Test 7: Method call on existing method
|
64
|
+
(function() {
|
65
|
+
const obj = {
|
66
|
+
method: function() { return 'result'; }
|
67
|
+
};
|
68
|
+
assert(obj?.method?.() === 'result', 'Method call on existing method failed');
|
69
|
+
console.log('✓ Method call on existing method');
|
70
|
+
})();
|
71
|
+
|
72
|
+
// Test 8: Method call on undefined object
|
73
|
+
(function() {
|
74
|
+
const obj = undefined;
|
75
|
+
assert(obj?.method?.() === undefined, 'Method call on undefined object failed');
|
76
|
+
console.log('✓ Method call on undefined object');
|
77
|
+
})();
|
78
|
+
|
79
|
+
// Test 9: Method call on null method
|
80
|
+
(function() {
|
81
|
+
const obj = { method: null };
|
82
|
+
assert(obj?.method?.() === undefined, 'Method call on null method failed');
|
83
|
+
console.log('✓ Method call on null method');
|
84
|
+
})();
|
85
|
+
|
86
|
+
// Test 10: Method call on undefined method
|
87
|
+
(function() {
|
88
|
+
const obj = {};
|
89
|
+
assert(obj?.method?.() === undefined, 'Method call on undefined method failed');
|
90
|
+
console.log('✓ Method call on undefined method');
|
91
|
+
})();
|
92
|
+
|
93
|
+
// ARRAY ELEMENT ACCESS TESTS
|
94
|
+
console.log('\n=== Array Element Access ===');
|
95
|
+
|
96
|
+
// Test 11: Array element access with valid index
|
97
|
+
(function() {
|
98
|
+
const arr = [1, 2, 3];
|
99
|
+
assert(arr?.[1] === 2, 'Array element access with valid index failed');
|
100
|
+
console.log('✓ Array element access with valid index');
|
101
|
+
})();
|
102
|
+
|
103
|
+
// Test 12: Array element access with undefined array
|
104
|
+
(function() {
|
105
|
+
const arr = undefined;
|
106
|
+
assert(arr?.[1] === undefined, 'Array element access with undefined array failed');
|
107
|
+
console.log('✓ Array element access with undefined array');
|
108
|
+
})();
|
109
|
+
|
110
|
+
// Test 13: Array element access with null array
|
111
|
+
(function() {
|
112
|
+
const arr = null;
|
113
|
+
assert(arr?.[1] === undefined, 'Array element access with null array failed');
|
114
|
+
console.log('✓ Array element access with null array');
|
115
|
+
})();
|
116
|
+
|
117
|
+
// Test 14: Access array method with optional chaining
|
118
|
+
(function() {
|
119
|
+
const arr = [1, 2, 3];
|
120
|
+
assert(arr?.map(x => x * 2)?.[0] === 2, 'Access array method with optional chaining failed');
|
121
|
+
console.log('✓ Access array method with optional chaining');
|
122
|
+
})();
|
123
|
+
|
124
|
+
// MIXED SYNTAX TESTS
|
125
|
+
console.log('\n=== Mixed Syntax Tests ===');
|
126
|
+
|
127
|
+
// Test 15: Mix of array and object property access
|
128
|
+
(function() {
|
129
|
+
const obj = { arr: [{ val: 42 }] };
|
130
|
+
assert(obj?.arr?.[0]?.val === 42, 'Mix of array and object property access failed');
|
131
|
+
console.log('✓ Mix of array and object property access');
|
132
|
+
})();
|
133
|
+
|
134
|
+
// Test 16: Method returning object with property
|
135
|
+
(function() {
|
136
|
+
const obj = {
|
137
|
+
getObject: function() { return { prop: 'value' }; }
|
138
|
+
};
|
139
|
+
assert(obj?.getObject?.()?.prop === 'value', 'Method returning object with property failed');
|
140
|
+
console.log('✓ Method returning object with property');
|
141
|
+
})();
|
142
|
+
|
143
|
+
// Test 17: Object with method returning array
|
144
|
+
(function() {
|
145
|
+
const obj = {
|
146
|
+
getArray: function() { return [1, 2, 3]; }
|
147
|
+
};
|
148
|
+
assert(obj?.getArray?.()?.[1] === 2, 'Object with method returning array failed');
|
149
|
+
console.log('✓ Object with method returning array');
|
150
|
+
})();
|
151
|
+
|
152
|
+
// COMPLEX EXPRESSIONS AND EDGE CASES
|
153
|
+
console.log('\n=== Complex Expressions and Edge Cases ===');
|
154
|
+
|
155
|
+
// Test 18: Optional chaining with function arguments
|
156
|
+
(function() {
|
157
|
+
const obj = {
|
158
|
+
method: function(a, b) { return a + b; }
|
159
|
+
};
|
160
|
+
assert(obj?.method?.(1, 2) === 3, 'Optional chaining with function arguments failed');
|
161
|
+
console.log('✓ Optional chaining with function arguments');
|
162
|
+
})();
|
163
|
+
|
164
|
+
// Test 19: Optional chaining in expressions
|
165
|
+
(function() {
|
166
|
+
const obj = { a: 5 };
|
167
|
+
assert((obj?.a + 5) === 10, 'Optional chaining in expressions failed');
|
168
|
+
console.log('✓ Optional chaining in expressions');
|
169
|
+
})();
|
170
|
+
|
171
|
+
// Test 20: Optional chaining with property names containing special characters
|
172
|
+
(function() {
|
173
|
+
const obj = { 'special-prop': 42 };
|
174
|
+
assert(obj?.['special-prop'] === 42, 'Optional chaining with property names containing special characters failed');
|
175
|
+
console.log('✓ Optional chaining with property names containing special characters');
|
176
|
+
})();
|
177
|
+
|
178
|
+
// Test 21: Optional chaining with computed property names
|
179
|
+
(function() {
|
180
|
+
const key = 'dynamicKey';
|
181
|
+
const obj = { dynamicKey: 'dynamic value' };
|
182
|
+
assert(obj?.[key] === 'dynamic value', 'Optional chaining with computed property names failed');
|
183
|
+
console.log('✓ Optional chaining with computed property names');
|
184
|
+
})();
|
185
|
+
|
186
|
+
// Test 22: Optional chaining with Symbol properties
|
187
|
+
(function() {
|
188
|
+
const sym = Symbol('test');
|
189
|
+
const obj = {};
|
190
|
+
obj[sym] = 'symbol value';
|
191
|
+
assert(obj?.[sym] === 'symbol value', 'Optional chaining with Symbol properties failed');
|
192
|
+
console.log('✓ Optional chaining with Symbol properties');
|
193
|
+
})();
|
194
|
+
|
195
|
+
// Test 23: Optional chaining with object returned from function
|
196
|
+
(function() {
|
197
|
+
function getObject(returnValue) {
|
198
|
+
return returnValue ? { prop: 'exists' } : null;
|
199
|
+
}
|
200
|
+
assert(getObject(true)?.prop === 'exists', 'Optional chaining with object returned from function (true case) failed');
|
201
|
+
assert(getObject(false)?.prop === undefined, 'Optional chaining with object returned from function (false case) failed');
|
202
|
+
console.log('✓ Optional chaining with object returned from function');
|
203
|
+
})();
|
204
|
+
|
205
|
+
// Test 24: Optional chaining with prototype chain
|
206
|
+
(function() {
|
207
|
+
const proto = { inheritedProp: 'inherited' };
|
208
|
+
const obj = Object.create(proto);
|
209
|
+
assert(obj?.inheritedProp === 'inherited', 'Optional chaining with prototype chain failed');
|
210
|
+
console.log('✓ Optional chaining with prototype chain');
|
211
|
+
})();
|
212
|
+
|
213
|
+
// Test 25: Optional chaining with getters
|
214
|
+
(function() {
|
215
|
+
const obj = {
|
216
|
+
get prop() { return 'getter value'; }
|
217
|
+
};
|
218
|
+
assert(obj?.prop === 'getter value', 'Optional chaining with getters failed');
|
219
|
+
console.log('✓ Optional chaining with getters');
|
220
|
+
})();
|
221
|
+
|
222
|
+
// SHORT-CIRCUIT EVALUATION TESTS
|
223
|
+
console.log('\n=== Short-circuit Evaluation Tests ===');
|
224
|
+
|
225
|
+
// Test 26: Short-circuit evaluation - should not call function after undefined
|
226
|
+
(function() {
|
227
|
+
let functionCalled = false;
|
228
|
+
const obj = undefined;
|
229
|
+
|
230
|
+
function sideEffect() {
|
231
|
+
functionCalled = true;
|
232
|
+
return 'side effect';
|
233
|
+
}
|
234
|
+
|
235
|
+
obj?.prop?.[sideEffect()];
|
236
|
+
assert(functionCalled === false, 'Short-circuit evaluation failed - function called when it should not have been');
|
237
|
+
console.log('✓ Short-circuit evaluation - function not called after undefined');
|
238
|
+
})();
|
239
|
+
|
240
|
+
// Test 27: Non-short-circuit evaluation - should call function when property exists
|
241
|
+
(function() {
|
242
|
+
let functionCalled = false;
|
243
|
+
const obj = { prop: {} };
|
244
|
+
|
245
|
+
function sideEffect() {
|
246
|
+
functionCalled = true;
|
247
|
+
return 'key';
|
248
|
+
}
|
249
|
+
|
250
|
+
obj?.prop?.[sideEffect()];
|
251
|
+
assert(functionCalled === true, 'Non-short-circuit evaluation failed - function not called when it should have been');
|
252
|
+
console.log('✓ Non-short-circuit evaluation - function called when property exists');
|
253
|
+
})();
|
254
|
+
|
255
|
+
// ASSIGNMENT AND DESTRUCTURING TESTS
|
256
|
+
console.log('\n=== Assignment and Destructuring Tests ===');
|
257
|
+
|
258
|
+
// Test 28: Optional chaining in destructuring
|
259
|
+
(function() {
|
260
|
+
const obj = { nested: { value: 42 } };
|
261
|
+
const { nested: { value } = {} } = obj ?? {};
|
262
|
+
assert(value === 42, 'Optional chaining in destructuring failed');
|
263
|
+
console.log('✓ Optional chaining in destructuring');
|
264
|
+
})();
|
265
|
+
|
266
|
+
// Test 29: Optional chaining with the nullish coalescing operator
|
267
|
+
(function() {
|
268
|
+
const obj = null;
|
269
|
+
const value = obj?.prop ?? 'default';
|
270
|
+
assert(value === 'default', 'Optional chaining with nullish coalescing operator failed');
|
271
|
+
console.log('✓ Optional chaining with nullish coalescing operator');
|
272
|
+
})();
|
273
|
+
|
274
|
+
// Test 30: Optional chaining in logical expressions
|
275
|
+
(function() {
|
276
|
+
const obj = { prop: true };
|
277
|
+
const nullObj = null;
|
278
|
+
|
279
|
+
assert((obj?.prop && 'yes') === 'yes', 'Optional chaining in logical AND expression failed');
|
280
|
+
assert((nullObj?.prop && 'yes') === undefined, 'Optional chaining in logical AND expression with null failed');
|
281
|
+
assert((obj?.prop || 'fallback') === true, 'Optional chaining in logical OR expression failed');
|
282
|
+
assert((nullObj?.prop || 'fallback') === 'fallback', 'Optional chaining in logical OR expression with null failed');
|
283
|
+
|
284
|
+
console.log('✓ Optional chaining in logical expressions');
|
285
|
+
})();
|
286
|
+
|
287
|
+
// PERFORMANCE EDGE CASES
|
288
|
+
console.log('\n=== Performance Edge Cases ===');
|
289
|
+
|
290
|
+
// Test 31: Deep nesting - many levels
|
291
|
+
(function() {
|
292
|
+
const obj = { a: { b: { c: { d: { e: { f: { g: { h: { i: { j: 'deep' } } } } } } } } } };
|
293
|
+
assert(obj?.a?.b?.c?.d?.e?.f?.g?.h?.i?.j === 'deep', 'Deep nesting optional chaining failed');
|
294
|
+
console.log('✓ Deep nesting - many levels');
|
295
|
+
})();
|
296
|
+
|
297
|
+
// Test 32: Complex real-world scenario
|
298
|
+
(function() {
|
299
|
+
const data = {
|
300
|
+
user: {
|
301
|
+
profile: {
|
302
|
+
name: 'John',
|
303
|
+
address: {
|
304
|
+
city: 'New York',
|
305
|
+
zipcode: '10001'
|
306
|
+
}
|
307
|
+
},
|
308
|
+
preferences: {
|
309
|
+
theme: 'dark',
|
310
|
+
notifications: {
|
311
|
+
email: true,
|
312
|
+
sms: false
|
313
|
+
}
|
314
|
+
},
|
315
|
+
friends: [
|
316
|
+
{ id: 1, name: 'Alice' },
|
317
|
+
{ id: 2, name: 'Bob' }
|
318
|
+
]
|
319
|
+
}
|
320
|
+
};
|
321
|
+
|
322
|
+
// Multiple complex optional chaining expressions
|
323
|
+
assert(data?.user?.profile?.name === 'John', 'Complex scenario - user name test failed');
|
324
|
+
assert(data?.user?.profile?.address?.city === 'New York', 'Complex scenario - address city test failed');
|
325
|
+
assert(data?.user?.preferences?.notifications?.email === true, 'Complex scenario - notifications email test failed');
|
326
|
+
assert(data?.user?.friends?.[1]?.name === 'Bob', 'Complex scenario - friends name test failed');
|
327
|
+
assert(data?.user?.nonexistent?.something === undefined, 'Complex scenario - nonexistent property test failed');
|
328
|
+
|
329
|
+
console.log('✓ Complex real-world scenario');
|
330
|
+
})();
|
331
|
+
|
332
|
+
// SUMMARY
|
333
|
+
console.log('\n=== Test Summary ===');
|
334
|
+
console.log('All tests completed successfully!');
|
335
|
+
console.log('Total tests: 32');
|
package/package.json
CHANGED