porffor 0.56.7 → 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.
@@ -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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.56.7",
4
+ "version": "0.56.8",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.56.7';
3
+ globalThis.version = '0.56.8';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {