rip-lang 1.0.0

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.
Files changed (80) hide show
  1. package/.cursor/rules/rip-agent-onboarding.md +681 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.yml +98 -0
  3. package/.github/ISSUE_TEMPLATE/coffeescript_compatibility.yml +86 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +9 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +82 -0
  6. package/.github/ISSUE_TEMPLATE/question.yml +55 -0
  7. package/.github/pull_request_template.md +84 -0
  8. package/AGENT.md +623 -0
  9. package/CONTRIBUTING.md +331 -0
  10. package/LICENSE +21 -0
  11. package/README.md +1245 -0
  12. package/SETUP.md +144 -0
  13. package/bar.coffee +394 -0
  14. package/bin/rip +162 -0
  15. package/bunfig.toml +11 -0
  16. package/docs/BROWSER.md +983 -0
  17. package/docs/CODEGEN.md +1023 -0
  18. package/docs/COFFEESCRIPT-COMPARISON.md +740 -0
  19. package/docs/COMPREHENSIONS.md +572 -0
  20. package/docs/REGEX-PLUS.md +441 -0
  21. package/docs/SOLAR.md +846 -0
  22. package/docs/SPECIAL-OPERATORS.md +769 -0
  23. package/docs/STRING.md +363 -0
  24. package/docs/WHY-NOT-COFFEESCRIPT.md +184 -0
  25. package/docs/WHY-YES-RIP.md +690 -0
  26. package/docs/WORKFLOW.md +306 -0
  27. package/docs/dist/rip.browser.js +6798 -0
  28. package/docs/dist/rip.browser.min.js +242 -0
  29. package/docs/dist/rip.browser.min.js.br +0 -0
  30. package/docs/example.html +177 -0
  31. package/docs/examples/README.md +154 -0
  32. package/docs/examples/arrows.rip +84 -0
  33. package/docs/examples/async-await.rip +59 -0
  34. package/docs/examples/existential.rip +86 -0
  35. package/docs/examples/fibonacci.rip +12 -0
  36. package/docs/examples/module.rip +38 -0
  37. package/docs/examples/object-syntax.rip +74 -0
  38. package/docs/examples/prototype.rip +30 -0
  39. package/docs/examples/ranges.rip +45 -0
  40. package/docs/examples/switch.rip +50 -0
  41. package/docs/examples/ternary.rip +36 -0
  42. package/docs/examples/use-loader.js +9 -0
  43. package/docs/examples/utils.rip +20 -0
  44. package/docs/index.html +65 -0
  45. package/docs/repl.html +914 -0
  46. package/docs/rip-1280w.png +0 -0
  47. package/docs/rip.svg +4 -0
  48. package/package.json +52 -0
  49. package/rip-loader.ts +27 -0
  50. package/scripts/build-browser.js +76 -0
  51. package/scripts/serve.js +71 -0
  52. package/src/browser.js +97 -0
  53. package/src/codegen.js +4808 -0
  54. package/src/compiler.js +270 -0
  55. package/src/grammar/grammar.rip +801 -0
  56. package/src/grammar/solar.rip +1056 -0
  57. package/src/lexer.js +3145 -0
  58. package/src/parser.js +352 -0
  59. package/src/repl.js +423 -0
  60. package/test/rip/assignment.rip +115 -0
  61. package/test/rip/async.rip +361 -0
  62. package/test/rip/basic.rip +171 -0
  63. package/test/rip/classes.rip +167 -0
  64. package/test/rip/compatibility.rip +338 -0
  65. package/test/rip/comprehensions.rip +104 -0
  66. package/test/rip/control.rip +177 -0
  67. package/test/rip/data.rip +215 -0
  68. package/test/rip/errors.rip +129 -0
  69. package/test/rip/functions.rip +443 -0
  70. package/test/rip/guards.rip +247 -0
  71. package/test/rip/literals.rip +131 -0
  72. package/test/rip/loops.rip +117 -0
  73. package/test/rip/modules.rip +87 -0
  74. package/test/rip/operators.rip +158 -0
  75. package/test/rip/optional.rip +184 -0
  76. package/test/rip/properties.rip +94 -0
  77. package/test/rip/regex.rip +301 -0
  78. package/test/rip/stabilization.rip +825 -0
  79. package/test/rip/strings.rip +483 -0
  80. package/test/runner.js +329 -0
@@ -0,0 +1,443 @@
1
+ # Test: Function Definitions (1 node type)
2
+ # Tests "def" node type
3
+
4
+ # ============================================================================
5
+ # Function Definitions: "def"
6
+ # ============================================================================
7
+
8
+ # Simple function
9
+ test "simple function", "def add(a, b)\n a + b\nadd(2, 3)", 5
10
+ test "function with no params", "def greet\n 'hello'\ngreet()", "hello"
11
+
12
+ # Function with body
13
+ test "function with multiple statements", "def fn\n x = 5\n y = 10\n x + y\nfn()", 15
14
+
15
+ # Code generation
16
+ code "simple def", "def add(a, b)\n a + b", "function add(a, b) { return (a + b); }"
17
+
18
+ # Implicit return
19
+ test "implicit return", "def getValue\n 42\ngetValue()", 42
20
+ test "implicit return last statement", "def fn\n x = 1\n x + 1\nfn()", 2
21
+
22
+ # Function calling other functions
23
+ test "function calling function", "def double(x)\n x * 2\ndef quad(x)\n double(double(x))\nquad(3)", 12
24
+
25
+ # Recursive functions
26
+ test "recursive factorial", "def factorial(n)\n if n <= 1\n 1\n else\n n * factorial(n - 1)\nfactorial(5)", 120
27
+
28
+ # ============================================================================
29
+ # Async Functions (auto-detection)
30
+ # ============================================================================
31
+
32
+ test "async function", "def fetchData\n await Promise.resolve(42)\nfetchData()", 42
33
+
34
+ # ============================================================================
35
+ # Stats for CODEGEN.md
36
+ # ============================================================================
37
+ # Function definitions implemented: 0/1 (0%)
38
+ # Tests passing: 0/10 (0%)
39
+ # Test: Arrow Functions (2 node types)
40
+ # Tests "->" (thin arrow) and "=>" (fat arrow) node types
41
+
42
+ # ============================================================================
43
+ # Thin Arrow: "->"
44
+ # ============================================================================
45
+
46
+ # Basic thin arrow
47
+ test "thin arrow simple", "add = (a, b) -> a + b\nadd(2, 3)", 5
48
+ test "thin arrow no params", "greet = -> 'hello'\ngreet()", "hello"
49
+ test "thin arrow one param", "double = (x) -> x * 2\ndouble(5)", 10
50
+
51
+ # Code generation
52
+ code "thin arrow", "(a, b) -> a + b", "function(a, b) { return (a + b); }"
53
+
54
+ # Thin arrow with block body
55
+ test "thin arrow block", "fn = ->\n x = 5\n x * 2\nfn()", 10
56
+
57
+ # Implicit return
58
+ test "thin arrow implicit return", "getValue = -> 42\ngetValue()", 42
59
+
60
+ # Thin arrow 'this' binding (call-site determined)
61
+ test "thin arrow this call-site", "obj = {x: 5, fn: -> this.x}\nobj.fn()", 5
62
+
63
+ # ============================================================================
64
+ # Fat Arrow: "=>"
65
+ # ============================================================================
66
+
67
+ # Basic fat arrow
68
+ test "fat arrow simple", "add = (a, b) => a + b\nadd(2, 3)", 5
69
+ test "fat arrow no params", "greet = => 'hello'\ngreet()", "hello"
70
+ test "fat arrow one param", "double = (x) => x * 2\ndouble(5)", 10
71
+
72
+ # Code generation
73
+ code "fat arrow", "(a, b) => a + b", "(a, b) => (a + b)"
74
+
75
+ # Fat arrow with block body
76
+ test "fat arrow block", "fn = =>\n x = 5\n x * 2\nfn()", 10
77
+
78
+ # Fat arrow 'this' binding (lexically bound to outer scope)
79
+ test "fat arrow this lexical", "obj = {x: 5, fn: => this?.x}\nobj.fn()", undefined
80
+
81
+ # ============================================================================
82
+ # Arrow Functions in Collections
83
+ # ============================================================================
84
+
85
+ # Arrow in array
86
+ test "arrow in array", "fns = [(x) -> x + 1, (x) -> x * 2]\nfns[0](5)", 6
87
+
88
+ # Arrow in object
89
+ test "arrow in object", "obj = {fn: (x) -> x * 2}\nobj.fn(5)", 10
90
+
91
+ # ============================================================================
92
+ # Stats for CODEGEN.md
93
+ # ============================================================================
94
+ # Arrow functions implemented: 0/2 (0%)
95
+ # Tests passing: 0/16 (0%)
96
+ # Test: Function Calls (1 node type)
97
+ # Tests function call pattern (array with non-string head)
98
+
99
+ # ============================================================================
100
+ # Function Calls
101
+ # ============================================================================
102
+
103
+ # Simple calls
104
+ test "call no args", "fn = -> 42\nfn()", 42
105
+ test "call with args", "add = (a, b) -> a + b\nadd(2, 3)", 5
106
+ test "call with multiple args", "sum = (a, b, c) -> a + b + c\nsum(1, 2, 3)", 6
107
+
108
+ # Code generation
109
+ code "simple call", "fn()", "fn()"
110
+ code "call with args", "fn(a, b)", "fn(a, b)"
111
+
112
+ # Nested calls
113
+ test "nested calls", "double = (x) -> x * 2\ntriple = (x) -> x * 3\ndouble(triple(2))", 12
114
+
115
+ # Calls with expressions
116
+ test "call with expression arg", "double = (x) -> x * 2\ndouble(2 + 3)", 10
117
+
118
+ # Method calls
119
+ test "method call", "obj = {fn: -> 42}\nobj.fn()", 42
120
+
121
+ # ============================================================================
122
+ # Spread in Calls: "..."
123
+ # ============================================================================
124
+
125
+ # Spread arguments
126
+ test "spread args", "add = (a, b, c) -> a + b + c\nargs = [1, 2, 3]\nadd(...args)", 6
127
+ test "spread with other args", "fn = (a, b, c) -> a + b + c\nfn(1, ...[2, 3])", 6
128
+
129
+ # ============================================================================
130
+ # Stats for CODEGEN.md
131
+ # ============================================================================
132
+ # Function calls implemented: 0/1 (0%)
133
+ # Tests passing: 0/10 (0%)
134
+ # Test: Function Parameters (3 node types)
135
+ # Tests "rest", "...", and "default" node types
136
+
137
+ # ============================================================================
138
+ # Rest Parameters: "rest"
139
+ # ============================================================================
140
+
141
+ # Basic rest parameters
142
+ test "rest params", "fn = (first, ...rest) -> rest.length\nfn(1, 2, 3, 4)", 3
143
+ test "rest params values", "fn = (first, ...rest) -> rest[0]\nfn(1, 2, 3)", 2
144
+ test "rest params empty", "fn = (...rest) -> rest.length\nfn()", 0
145
+
146
+ # Code generation
147
+ code "rest params", "(first, ...rest) -> rest", "function(first, ...rest) { return rest; }"
148
+
149
+ # Rest with no other params
150
+ test "rest only", "fn = (...all) -> all.length\nfn(1, 2, 3)", 3
151
+
152
+ # Rest in middle position (CoffeeScript expansion marker)
153
+ test "rest in middle", '''
154
+ fn = (first, middle..., last) ->
155
+ [first, middle.length, last]
156
+ fn(1, 2, 3, 4, 5)
157
+ ''', [1, 3, 5]
158
+
159
+ test "rest in middle with two after", '''
160
+ fn = (a, mid..., b, c) ->
161
+ [a, mid, b, c]
162
+ fn(1, 2, 3, 4, 5)
163
+ ''', [1, [2, 3], 4, 5]
164
+
165
+ # ============================================================================
166
+ # Default Parameters: "default"
167
+ # ============================================================================
168
+
169
+ # Basic default parameters
170
+ test "default param used", "fn = (x = 10) -> x\nfn()", 10
171
+ test "default param override", "fn = (x = 10) -> x\nfn(20)", 20
172
+ test "default param expression", "fn = (x = 5 + 5) -> x\nfn()", 10
173
+
174
+ # Code generation
175
+ code "default param", "(x = 10) -> x", "function(x = 10) { return x; }"
176
+
177
+ # Multiple default params
178
+ test "multiple defaults", "fn = (a = 1, b = 2) -> a + b\nfn()", 3
179
+ test "partial defaults", "fn = (a = 1, b = 2) -> a + b\nfn(5)", 7
180
+
181
+ # ============================================================================
182
+ # Expansion: "expansion"
183
+ # ============================================================================
184
+
185
+ # Expansion marker: (a, ..., b)
186
+ test "expansion marker", "fn = (a, ..., b) -> a + b\nfn(1, 2, 3, 4)", 5
187
+
188
+ # ============================================================================
189
+ # Stats for CODEGEN.md
190
+ # ============================================================================
191
+ # Parameter types implemented: 0/3 (0%)
192
+ # Tests passing: 0/15 (0%)
193
+ # Test: Return Statements (1 node type)
194
+ # Tests "return" node type
195
+
196
+ # ============================================================================
197
+ # Return Statements: "return"
198
+ # ============================================================================
199
+
200
+ # Explicit return
201
+ test "explicit return", "fn = -> return 42\nfn()", 42
202
+ test "early return", "fn = (x) ->\n return 1 if x < 0\n return 2\nfn(-5)", 1
203
+ test "return expression", "fn = -> return 5 + 10\nfn()", 15
204
+
205
+ # Code generation
206
+ code "simple return", "return 42", "return 42"
207
+ code "return expression", "return a + b", "return (a + b)"
208
+
209
+ # Return in different contexts
210
+ test "return in if", "fn = (x) ->\n if x > 0\n return 'positive'\n 'negative'\nfn(5)", "positive"
211
+
212
+ # Multiple returns
213
+ test "multiple returns", "fn = (x) ->\n return 1 if x == 1\n return 2 if x == 2\n return 3\nfn(2)", 2
214
+
215
+ # Return vs implicit return
216
+ test "explicit vs implicit", "fn = (x) ->\n if x > 0\n return x\n 0\nfn(5)", 5
217
+
218
+ # ============================================================================
219
+ # IIFE (Immediately Invoked Function Expression)
220
+ # ============================================================================
221
+
222
+ test "IIFE simple", "(-> 42)()", 42
223
+ test "IIFE with params", "((x) -> x * 2)(5)", 10
224
+ test "IIFE with block", "(-> \n x = 5\n x * 2)()", 10
225
+
226
+ # ============================================================================
227
+ # Closures
228
+ # ============================================================================
229
+
230
+ test "closure captures variable", '''
231
+ makeCounter = ->
232
+ count = 0
233
+ -> count++
234
+ counter = makeCounter()
235
+ counter()
236
+ counter()
237
+ counter()
238
+ ''', 2
239
+
240
+ test "closure multiple instances", '''
241
+ makeAdder = (n) ->
242
+ (x) -> x + n
243
+ add5 = makeAdder(5)
244
+ add10 = makeAdder(10)
245
+ add5(3) + add10(3)
246
+ ''', 21
247
+
248
+ # ============================================================================
249
+ # Higher-Order Functions
250
+ # ============================================================================
251
+
252
+ test "function returns function", '''
253
+ outer = (x) ->
254
+ (y) -> x + y
255
+ add5 = outer(5)
256
+ add5(3)
257
+ ''', 8
258
+
259
+ test "function takes function", '''
260
+ apply = (fn, x) -> fn(x)
261
+ double = (x) -> x * 2
262
+ apply(double, 5)
263
+ ''', 10
264
+
265
+ # ============================================================================
266
+ # Void Functions (! at definition - side-effect only)
267
+ # ============================================================================
268
+
269
+ test "void function no implicit return", '''
270
+ def process!
271
+ x = 42
272
+ x * 2
273
+ result = process()
274
+ result
275
+ ''', undefined
276
+
277
+ test "void function with params", '''
278
+ def update!(arr, val)
279
+ arr.push val
280
+ val * 2
281
+ arr = []
282
+ update(arr, 5)
283
+ arr
284
+ ''', [5]
285
+
286
+ test "void function with early return", '''
287
+ def validate!(x)
288
+ return if x < 0
289
+ console.log "valid"
290
+ x * 2
291
+ [validate(5), validate(-1)]
292
+ ''', [undefined, undefined]
293
+
294
+ test "void function return strips value", '''
295
+ def compute!(x)
296
+ return x * 10
297
+ result = compute(5)
298
+ result
299
+ ''', undefined
300
+
301
+ test "normal function for comparison", '''
302
+ def compute(x)
303
+ return x * 10
304
+ result = compute(5)
305
+ result
306
+ ''', 50
307
+
308
+ test "void function in loop", '''
309
+ results = []
310
+ def append!(val)
311
+ results.push val
312
+ for x in [1, 2, 3]
313
+ append(x)
314
+ results
315
+ ''', [1, 2, 3]
316
+
317
+ test "void function with comprehension", '''
318
+ def process!
319
+ for x in [1, 2, 3]
320
+ console.log x
321
+ result = process()
322
+ result
323
+ ''', undefined
324
+
325
+ code "void function no implicit return in codegen", '''
326
+ def process!
327
+ x = 42
328
+ x * 2
329
+ ''', '''
330
+ function process() {
331
+ let x;
332
+ x = 42;
333
+ (x * 2);
334
+ return;
335
+ }
336
+ '''
337
+
338
+ code "void function early return no value", '''
339
+ def validate!(x)
340
+ return if x < 0
341
+ console.log "ok"
342
+ ''', '''
343
+ function validate(x) {
344
+ if ((x < 0)) return;
345
+ console.log("ok");
346
+ return;
347
+ }
348
+ '''
349
+
350
+ code "void function strips return value", '''
351
+ def compute!(x)
352
+ return x * 2
353
+ ''', '''
354
+ function compute(x) {
355
+ return;
356
+ }
357
+ '''
358
+
359
+ # ============================================================================
360
+ # Void Arrow Functions (! with -> and =>)
361
+ # ============================================================================
362
+
363
+ test "void thin arrow no implicit return", '''
364
+ c! = ->
365
+ x = 42
366
+ x * 2
367
+ result = c()
368
+ result
369
+ ''', undefined
370
+
371
+ test "void thin arrow with params", '''
372
+ add! = (a, b) ->
373
+ a + b
374
+ result = add(5, 10)
375
+ result
376
+ ''', undefined
377
+
378
+ test "void thin arrow with return", '''
379
+ c! = ->
380
+ return "hello world"
381
+ result = c()
382
+ result
383
+ ''', undefined
384
+
385
+ test "void fat arrow no implicit return", '''
386
+ d! = =>
387
+ x = 100
388
+ x * 2
389
+ result = d()
390
+ result
391
+ ''', undefined
392
+
393
+ test "void fat arrow with params", '''
394
+ multiply! = (a, b) =>
395
+ a * b
396
+ result = multiply(3, 4)
397
+ result
398
+ ''', undefined
399
+
400
+ test "void fat arrow with comprehension", '''
401
+ d! = (e, f, g) =>
402
+ h = for i in [3..6]
403
+ i + 4
404
+ result = d(1, 2, 3)
405
+ result
406
+ ''', undefined
407
+
408
+ code "void thin arrow codegen", '''
409
+ c! = ->
410
+ return "hello world"
411
+ ''', '''
412
+ let c;
413
+ c = (function() {
414
+ return;
415
+ });
416
+ '''
417
+
418
+ code "void fat arrow codegen", '''
419
+ process! = (x) =>
420
+ x * 2
421
+ ''', '''
422
+ let process;
423
+ process = (x) => {
424
+ (x * 2);
425
+ return;
426
+ };
427
+ '''
428
+
429
+ # NOTE: Object method void syntax (fn!:) not yet supported by parser
430
+ # test "void arrow in object method", '''
431
+ # obj = {
432
+ # fn!: -> 42
433
+ # }
434
+ # result = obj.fn()
435
+ # result
436
+ # ''', undefined
437
+
438
+ # ============================================================================
439
+ # Stats for CODEGEN.md
440
+ # ============================================================================
441
+ # Node types: def, ->, =>, function calls, rest, ..., default, return, void functions (!)
442
+ # Tests: 81 total (81 passing, 0 failing)
443
+ # Coverage: Function definitions, arrows, calls, parameters, returns, IIFE, closures, higher-order functions, void functions (def and arrows)
@@ -0,0 +1,247 @@
1
+ # ==============================================================================
2
+ # Loop Guard Tests (when clause)
3
+ # ==============================================================================
4
+ #
5
+ # Tests for 'when' guards in for-in, for-of, while, and until loops.
6
+ # Guards filter iterations/executions based on a condition.
7
+ # ==============================================================================
8
+
9
+ # ==============================================================================
10
+ # FOR-IN GUARDS
11
+ # ==============================================================================
12
+
13
+ test 'for-in with simple guard', '''
14
+ result = []
15
+ for x in [1, 2, 3, 4, 5] when x > 2
16
+ result.push(x)
17
+ result
18
+ ''', [3, 4, 5]
19
+
20
+ test 'for-in guard with not', '''
21
+ result = []
22
+ for x in [1, 2, 3, 4, 5] when not (x is 3)
23
+ result.push(x)
24
+ result
25
+ ''', [1, 2, 4, 5]
26
+
27
+ test 'for-in guard with and', '''
28
+ result = []
29
+ for x in [1, 2, 3, 4, 5, 6] when x > 2 and x < 5
30
+ result.push(x)
31
+ result
32
+ ''', [3, 4]
33
+
34
+ test 'for-in guard with modulo', '''
35
+ result = []
36
+ for x in [1, 2, 3, 4, 5, 6] when x % 2 is 0
37
+ result.push(x)
38
+ result
39
+ ''', [2, 4, 6]
40
+
41
+ test 'for-in guard filtering strings', '''
42
+ result = []
43
+ for line in ["", "hello", "", "world", " "] when line and line.trim()
44
+ result.push(line)
45
+ result
46
+ ''', ["hello", "world"]
47
+
48
+ # ==============================================================================
49
+ # FOR-OF GUARDS
50
+ # ==============================================================================
51
+
52
+ test 'for-of with guard (key only)', '''
53
+ result = []
54
+ for k of {a: 1, b: 2, c: 3} when k isnt 'b'
55
+ result.push(k)
56
+ result
57
+ ''', ["a", "c"]
58
+
59
+ test 'for-of guard key only comprehension', '''
60
+ result = (k for k of {a: 1, b: 2, c: 3} when k isnt 'b')
61
+ result
62
+ ''', ["a", "c"]
63
+
64
+ test 'for-of with guard single entry', '''
65
+ result = []
66
+ for k, v of {a: 1} when v > 0
67
+ result.push(k)
68
+ result
69
+ ''', ["a"]
70
+
71
+ test 'for-of guard single entry comprehension', '''
72
+ result = (k for k, v of {a: 1} when v > 0)
73
+ result
74
+ ''', ["a"]
75
+
76
+ test 'for-of with guard (key and value)', '''
77
+ result = []
78
+ for k, v of {a: 1, b: 2, c: 3, d: 4} when v > 2
79
+ result.push(k)
80
+ result
81
+ ''', ["c", "d"]
82
+
83
+ test 'for-of guard complex condition', '''
84
+ obj = {x: 10, y: 20, z: 30}
85
+ sum = 0
86
+ for key, val of obj when val >= 20
87
+ sum += val
88
+ sum
89
+ ''', 50
90
+
91
+ # ==============================================================================
92
+ # COMPREHENSIONS WITH GUARDS
93
+ # ==============================================================================
94
+
95
+ test 'comprehension with guard', '''
96
+ result = (x for x in [1, 2, 3, 4, 5] when x > 2)
97
+ result
98
+ ''', [3, 4, 5]
99
+
100
+ test 'comprehension guard with not', '''
101
+ result = (x for x in [1, 2, 3, 4, 5] when not (x is 3))
102
+ result
103
+ ''', [1, 2, 4, 5]
104
+
105
+ test 'comprehension guard complex', '''
106
+ result = (x * 2 for x in [1, 2, 3, 4, 5, 6] when x % 2 is 0 and x < 5)
107
+ result
108
+ ''', [4, 8]
109
+
110
+ test 'object comprehension with guard', '''
111
+ result = {k: v for k, v of {a: 1, b: 2, c: 3} when v > 1}
112
+ result.b
113
+ ''', 2
114
+
115
+ # ==============================================================================
116
+ # EDGE CASES
117
+ # ==============================================================================
118
+
119
+ test 'guard with method call', '''
120
+ items = ["hello", "", "world", " "]
121
+ result = []
122
+ for item in items when item.trim()
123
+ result.push(item)
124
+ result
125
+ ''', ["hello", "world"]
126
+
127
+ test 'guard with property access', '''
128
+ objects = [{ok: true, val: 1}, {ok: false, val: 2}, {ok: true, val: 3}]
129
+ sum = 0
130
+ for obj in objects when obj.ok
131
+ sum += obj.val
132
+ sum
133
+ ''', 4
134
+
135
+ test 'guard with negated method', '''
136
+ lines = ["# comment", "data", "# another", "more"]
137
+ result = []
138
+ for line in lines when not line.startsWith("#")
139
+ result.push(line)
140
+ result
141
+ ''', ["data", "more"]
142
+
143
+ # ==============================================================================
144
+ # OWN KEYWORD (for-of only)
145
+ # ==============================================================================
146
+
147
+ test 'own filters inherited properties', '''
148
+ obj = Object.create({inherited: 'parent'})
149
+ obj.own1 = 'value1'
150
+ obj.own2 = 'value2'
151
+ result = []
152
+ for own k of obj
153
+ result.push(k)
154
+ result
155
+ ''', ["own1", "own2"]
156
+
157
+ test 'own with key and value', '''
158
+ obj = Object.create({inherited: 99})
159
+ obj.a = 1
160
+ obj.b = 2
161
+ sum = 0
162
+ for own k, v of obj
163
+ sum += v
164
+ sum
165
+ ''', 3
166
+
167
+ test 'own with guard', '''
168
+ obj = Object.create({inherited: 0})
169
+ obj.a = 1
170
+ obj.b = 2
171
+ obj.c = 3
172
+ result = []
173
+ for own k, v of obj when v > 1
174
+ result.push(k)
175
+ result
176
+ ''', ["b", "c"]
177
+
178
+ test 'own in comprehension', '''
179
+ obj = Object.create({inherited: 'x'})
180
+ obj.a = 1
181
+ obj.b = 2
182
+ result = (k for own k of obj)
183
+ result
184
+ ''', ["a", "b"]
185
+
186
+ test 'own in object comprehension', '''
187
+ obj = Object.create({inherited: 99})
188
+ obj.a = 1
189
+ obj.b = 2
190
+ result = {k: v for own k, v of obj}
191
+ Object.keys(result).sort()
192
+ ''', ["a", "b"]
193
+
194
+ test 'own with guard in comprehension', '''
195
+ obj = Object.create({inherited: 0})
196
+ obj.a = 1
197
+ obj.b = 2
198
+ obj.c = 3
199
+ result = (k for own k, v of obj when v > 1)
200
+ result
201
+ ''', ["b", "c"]
202
+
203
+ # ==============================================================================
204
+ # CODE GENERATION TESTS
205
+ # ==============================================================================
206
+
207
+ code 'for-in guard code', '''
208
+ for x in arr when x > 5
209
+ console.log x
210
+ ''', '''
211
+ for (const x of arr) {
212
+ if (x > 5) {
213
+ console.log(x);
214
+ }
215
+ }
216
+ '''
217
+
218
+ code 'for-of guard code', '''
219
+ for k, v of obj when v > 0
220
+ console.log k
221
+ ''', '''
222
+ for (const k in obj) {
223
+ const v = obj[k];
224
+ if ((v > 0)) {
225
+ console.log(k);
226
+ }
227
+ }
228
+ '''
229
+
230
+ code 'for-of with own code', '''
231
+ for own k, v of obj
232
+ console.log k
233
+ ''', '''
234
+ for (const k in obj) {
235
+ if (obj.hasOwnProperty(k)) {
236
+ const v = obj[k];
237
+ console.log(k);
238
+ }
239
+ }
240
+ '''
241
+
242
+ # ============================================================================
243
+ # Stats for CODEGEN.md
244
+ # ============================================================================
245
+ # Node types: for-in/for-of guards (when clause), own keyword (for-of only)
246
+ # Tests: 27 total (24 execution + 3 code generation, 27 passing, 0 failing)
247
+ # Coverage: Guards in all loop types, own keyword filtering inherited properties, combined own+guard