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,131 @@
1
+ # Test: Literals (5 node types)
2
+ # Tests NUMBER, undefined, null, BOOL, this node types
3
+
4
+ # ============================================================================
5
+ # Number Literals: NUMBER
6
+ # ============================================================================
7
+
8
+ # Integers
9
+ test "integer literal", "42", 42
10
+ test "negative integer", "-10", -10
11
+ test "zero", "0", 0
12
+
13
+ # Decimals
14
+ test "decimal literal", "3.14", 3.14
15
+ test "decimal negative", "-2.5", -2.5
16
+
17
+ # Special number formats
18
+ test "hex literal", "0xFF", 255
19
+ test "binary literal", "0b1010", 10
20
+ test "octal literal", "0o777", 511
21
+ test "scientific notation", "1.5e3", 1500
22
+ test "number with underscores", "1_000_000", 1000000
23
+
24
+ # Code generation
25
+ code "integer", "42", "42"
26
+ code "decimal", "3.14", "3.14"
27
+ code "hex", "0xFF", "0xFF"
28
+
29
+ # ============================================================================
30
+ # Undefined: "undefined"
31
+ # ============================================================================
32
+
33
+ test "undefined literal", "undefined", undefined
34
+
35
+ # Code generation
36
+ code "undefined", "undefined", "undefined"
37
+
38
+ # ============================================================================
39
+ # Null: "null"
40
+ # ============================================================================
41
+
42
+ test "null literal", "null", null
43
+
44
+ # Code generation
45
+ code "null", "null", "null"
46
+
47
+ # ============================================================================
48
+ # Boolean: BOOL
49
+ # ============================================================================
50
+
51
+ test "true literal", "true", true
52
+ test "false literal", "false", false
53
+
54
+ # Code generation
55
+ code "true", "true", "true"
56
+ code "false", "false", "false"
57
+
58
+ # ============================================================================
59
+ # This: "this"
60
+ # ============================================================================
61
+
62
+ # Basic this
63
+ test "this in method", "obj = {x: 42, fn: -> this.x}\nobj.fn()", 42
64
+
65
+ # @ shorthand
66
+ test "@ shorthand", "obj = {x: 42, fn: -> @x}\nobj.fn()", 42
67
+
68
+ # Code generation
69
+ code "this keyword", "this", "this"
70
+ code "@ shorthand", "@", "this"
71
+
72
+ # ============================================================================
73
+ # Stats for CODEGEN.md
74
+ # ============================================================================
75
+ # Literal types implemented: 0/6 (0%)
76
+ # Tests passing: 0/20 (0%)
77
+ # Test: JavaScript Literals
78
+ # Inline JavaScript using backticks
79
+
80
+ # ============================================================================
81
+ # Inline JavaScript: backtick syntax
82
+ # ============================================================================
83
+
84
+ # Single-line inline JS
85
+ test 'inline JavaScript evaluation', '''
86
+ `var x = 5`
87
+ x
88
+ ''', 5
89
+
90
+ # Block inline JavaScript
91
+ test 'block inline JavaScript', '''
92
+ ```
93
+ let a = 1;
94
+ let b = 2;
95
+ ```
96
+ c = 3
97
+ a + b + c
98
+ ''', 6
99
+
100
+ # JS blocks mixed with Rip
101
+ test 'JS blocks mixed with Rip', '''
102
+ x = 1
103
+ ```
104
+ let y = 2;
105
+ ```
106
+ z = 3
107
+ x + y + z
108
+ ''', 6
109
+
110
+ # Inline JS with return value
111
+ test 'inline JS with return value', '''
112
+ result = `(function() { return 42; })()`
113
+ result
114
+ ''', 42
115
+
116
+ # Multiple JS blocks
117
+ test 'multiple JS variables', '''
118
+ ```
119
+ let a = 10;
120
+ let b = 20;
121
+ let c = 30;
122
+ ```
123
+ a + b + c
124
+ ''', 60
125
+
126
+ # ============================================================================
127
+ # Stats for CODEGEN.md
128
+ # ============================================================================
129
+ # Node types: NUMBER, undefined, null, BOOL, this, JS (backticks)
130
+ # Tests: 30 total (30 passing, 0 failing)
131
+ # Coverage: Numbers (decimal, hex, binary, octal, scientific), undefined, null, booleans, this/@, inline JS
@@ -0,0 +1,117 @@
1
+ # Test: Loops (5 node types)
2
+ # Tests "for-in", "for-of", "while", "until", "loop" node types
3
+
4
+ # ============================================================================
5
+ # For-In Loops (Array Iteration): "for-in"
6
+ # ============================================================================
7
+
8
+ # Basic for-in
9
+ test "for-in array", "sum = 0; for x in [1, 2, 3]\n sum += x\nsum", 6
10
+ test "for-in with index", "result = ''; for item, i in ['a', 'b', 'c']\n result += i\nresult", "012"
11
+ test "for-in range", "sum = 0; for i in [1..5]\n sum += i\nsum", 15
12
+
13
+ # Range loop without variable (N-time repetition)
14
+ test "range loop without var", "result = ''; for [1...5]\n result += 'x'\nresult", "xxxx"
15
+ test "range loop without var with by", "result = ''; for [1...10] by 2\n result += 'x'\nresult", "xxxxx"
16
+ test "postfix range without var", "result = ''; (result += 'x' for [1...5]); result", "xxxx"
17
+
18
+ # Code generation
19
+ code "for-in loop", "for x in arr\n x", "for (const x of arr) { x; }"
20
+ code "range loop no var", "for [1...5]\n doSomething()", "for (let _i = 1; _i < 5; _i++) {\n doSomething();\n}"
21
+
22
+ # ============================================================================
23
+ # For-Of Loops (Object Iteration): "for-of"
24
+ # ============================================================================
25
+
26
+ # Basic for-of
27
+ test "for-of object", "obj = {a: 1, b: 2}; sum = 0; for key, val of obj\n sum += val\nsum", 3
28
+ test "for-of keys only", "obj = {a: 1, b: 2}; keys = []; for key of obj\n keys.push(key)\nkeys.length", 2
29
+
30
+ # Code generation
31
+ code "for-of loop", "for k, v of obj\n v", "for (const k in obj) {\nconst v = obj[k];\nv;\n}"
32
+
33
+ # ============================================================================
34
+ # While Loops: "while"
35
+ # ============================================================================
36
+
37
+ # Basic while
38
+ test "while loop", "i = 0; sum = 0; while i < 5\n sum += i\n i += 1\nsum", 10
39
+
40
+ # While with guard
41
+ test "while when", "i = 0\nsum = 0\nwhile i < 10\n if i % 2 == 0\n sum += i\n i += 1\nsum", 20
42
+
43
+ # Postfix while
44
+ test "postfix while", "i = 0; i += 1 while i < 5; i", 5
45
+
46
+ # Code generation
47
+ code "while loop", "while cond\n body", "while (cond) { body; }"
48
+
49
+ # ============================================================================
50
+ # Until Loops: "until"
51
+ # ============================================================================
52
+
53
+ # Basic until
54
+ test "until loop", "i = 0; until i >= 5\n i += 1\ni", 5
55
+
56
+ # Until with guard
57
+ test "until when", "i = 0\nsum = 0\nuntil i >= 10\n if i % 2 == 0\n sum += i\n i += 1\nsum", 20
58
+
59
+ # Postfix until
60
+ test "postfix until", "i = 0; i += 1 until i >= 5; i", 5
61
+
62
+ # Code generation
63
+ code "until loop", "until cond\n body", "while (!cond) { body; }"
64
+
65
+ # ============================================================================
66
+ # Infinite Loops: "loop"
67
+ # ============================================================================
68
+
69
+ # Loop with break
70
+ test "loop with break", "i = 0; loop\n i += 1\n break if i >= 5\ni", 5
71
+
72
+ # Loop with continue
73
+ test "loop with continue", "i = 0; sum = 0; loop\n i += 1\n continue if i % 2 != 0\n sum += i\n break if i >= 10\nsum", 30
74
+
75
+ # Code generation
76
+ code "infinite loop", "loop\n body", "while (true) { body; }"
77
+
78
+ # ============================================================================
79
+ # Loop Control: break and continue
80
+ # ============================================================================
81
+
82
+ # Break statement
83
+ test "break in for-in", '''
84
+ sum = 0
85
+ for i in [1..10]
86
+ break if i > 5
87
+ sum += i
88
+ sum
89
+ ''', 15
90
+
91
+ # Continue statement
92
+ test "continue in for-in", '''
93
+ sum = 0
94
+ for i in [1..10]
95
+ continue if i % 2 == 0
96
+ sum += i
97
+ sum
98
+ ''', 25
99
+
100
+ # ============================================================================
101
+ # Nested Loops
102
+ # ============================================================================
103
+
104
+ test "nested for-in", '''
105
+ sum = 0
106
+ for i in [1, 2, 3]
107
+ for j in [10, 20]
108
+ sum += i * j
109
+ sum
110
+ ''', 180
111
+
112
+ # ============================================================================
113
+ # Stats for CODEGEN.md
114
+ # ============================================================================
115
+ # Node types: for-in, for-of, while, until, loop, break, continue, break-if, continue-if
116
+ # Tests: 25 total (25 passing, 0 failing)
117
+ # Coverage: Array iteration, object iteration, while/until, infinite loops, break, continue, nesting, range loops without variable
@@ -0,0 +1,87 @@
1
+ # Test: Modules (5 node types)
2
+ # Tests "import", "export", "export-default", "export-all", "export-from" node types
3
+
4
+ # ============================================================================
5
+ # Import: "import"
6
+ # ============================================================================
7
+
8
+ # Basic import
9
+ code "import default", 'import React from "react"', "import React from 'react';"
10
+ code "import named", 'import { useState } from "react"', "import { useState } from 'react';"
11
+ code "import namespace", 'import * as Utils from "./utils"', "import * as Utils from './utils.js';"
12
+
13
+ # Auto .js extension for local paths
14
+ code "import auto .js", 'import foo from "./foo"', "import foo from './foo.js';"
15
+ code "import preserve ext", 'import foo from "./foo.coffee"', "import foo from './foo.coffee';"
16
+
17
+ # JSON import assertions
18
+ code "import json", 'import data from "./config.json"', "import data from './config.json' with { type: 'json' };"
19
+
20
+ # Multiple imports in one file (import hoisting and path fixing)
21
+ code "multiple imports", "import React from \"react\"\nimport { useState } from \"react\"\nimport * as Utils from \"./utils\"\n\nx = 42\nconsole.log x", "import React from 'react';\nimport { useState } from 'react';\nimport * as Utils from './utils.js';\n\nlet x;\nx = 42;\nconsole.log(x);"
22
+
23
+ # Mixed imports (default + named/namespace)
24
+ code "import default and named", 'import React, { useState } from "react"', "import React, { useState } from 'react';"
25
+ code "import default and namespace", 'import React, * as ReactDOM from "react-dom"', "import React, * as ReactDOM from 'react-dom';"
26
+
27
+ # Import aliases
28
+ code "import alias", 'import { useState as useS } from "react"', "import { useState as useS } from 'react';"
29
+ code "import multiple aliases", 'import { useState as useS, useEffect as useE } from "react"', "import { useState as useS, useEffect as useE } from 'react';"
30
+
31
+ # ============================================================================
32
+ # Export: "export"
33
+ # ============================================================================
34
+
35
+ # Export variable
36
+ code "export var", "export x = 42", "export const x = 42;"
37
+
38
+ # Export function
39
+ code "export function", "export def add(a, b)\n a + b", "export function add(a, b) {\n return (a + b);\n};"
40
+
41
+ # Export class
42
+ code "export class", "export class Animal\n constructor: (@name) ->", "export class Animal {\n constructor(name) {\n this.name = name;\n }\n};"
43
+
44
+ # Named exports
45
+ code "export named", "export { x, y }", "export { x, y };"
46
+
47
+ # ============================================================================
48
+ # Export Default: "export-default"
49
+ # ============================================================================
50
+
51
+ # Export default value
52
+ code "export default value", "export default 42", "export default 42;"
53
+
54
+ # Export default function
55
+ code "export default function", "export default def greet(name)\n name", "export default function greet(name) {\n return name;\n};"
56
+
57
+ # Export default class
58
+ code "export default class", "export default class Animal", "export default class Animal {};"
59
+
60
+ # ============================================================================
61
+ # Export All: "export-all"
62
+ # ============================================================================
63
+
64
+ # Export all from module
65
+ code "export all", 'export * from "./utils"', "export * from './utils.js';"
66
+ code "export all json", 'export * from "./data.json"', "export * from './data.json' with { type: 'json' };"
67
+
68
+ # ============================================================================
69
+ # Export From: "export-from"
70
+ # ============================================================================
71
+
72
+ # Export named from module
73
+ code "export from", 'export { add, multiply } from "./math"', "export { add, multiply } from './math.js';"
74
+
75
+ # ============================================================================
76
+ # Meta Properties (ES6)
77
+ # ============================================================================
78
+
79
+ # import.meta (ES6 module meta property)
80
+ code "import.meta.url", 'x = import.meta.url', 'let x;\nx = import.meta.url'
81
+
82
+ # ============================================================================
83
+ # Stats for CODEGEN.md
84
+ # ============================================================================
85
+ # Node types: import, export, export-default, export-all, export-from, import.meta
86
+ # Tests: 23 total (23 code generation tests, can't execute due to import keyword)
87
+ # Coverage: import (default, named, namespace), export (var, function, class, named), auto .js extension, JSON imports, import.meta
@@ -0,0 +1,158 @@
1
+ # Test: Operators (24 node types)
2
+ # Systematically tests all operator node types from grammar
3
+
4
+ # ============================================================================
5
+ # Arithmetic Operators
6
+ # ============================================================================
7
+
8
+ # Addition: "+"
9
+ test "addition integers", "5 + 3", 8
10
+ test "addition decimals", "2.5 + 1.5", 4.0
11
+ test "addition negative", "-5 + 10", 5
12
+ code "addition parens", "a + b", "(a + b)"
13
+
14
+ # Subtraction: "-" (binary and unary)
15
+ test "subtraction integers", "10 - 4", 6
16
+ test "subtraction negative result", "3 - 5", -2
17
+ test "unary minus", "-5", -5
18
+ code "subtraction parens", "a - b", "(a - b)"
19
+
20
+ # Multiplication: "*"
21
+ test "multiplication", "4 * 3", 12
22
+ test "multiplication decimal", "2.5 * 2", 5.0
23
+ code "multiplication parens", "a * b", "(a * b)"
24
+
25
+ # Division: "/"
26
+ test "division", "10 / 2", 5
27
+ test "division decimal", "7 / 2", 3.5
28
+ code "division parens", "a / b", "(a / b)"
29
+
30
+ # Modulo: "%"
31
+ test "modulo", "10 % 3", 1
32
+ test "modulo zero", "10 % 5", 0
33
+ code "modulo parens", "a % b", "(a % b)"
34
+
35
+ # Exponentiation: "**"
36
+ test "exponentiation", "2 ** 3", 8
37
+ test "exponentiation decimal", "4 ** 0.5", 2
38
+ code "exponentiation parens", "a ** b", "(a ** b)"
39
+
40
+ # ============================================================================
41
+ # Comparison Operators
42
+ # ============================================================================
43
+
44
+ # Equality: "==" (compiles to strict ===)
45
+ test "equality true", "5 == 5", true
46
+ test "equality false", "5 == 3", false
47
+ test "is keyword", "5 is 5", true
48
+ test "is keyword false", "5 is 3", false
49
+ test "strict equality triple equals", "5 === 5", true
50
+ test "strict equality false", "5 === 3", false
51
+
52
+ code "equality compiles to strict", "a == b", "(a === b)"
53
+ code "is compiles to strict", "a is b", "(a === b)"
54
+ code "triple equals compiles to strict", "a === b", "(a === b)"
55
+
56
+ # Inequality: "!=" (compiles to strict !==)
57
+ test "inequality true", "5 != 3", true
58
+ test "inequality false", "5 != 5", false
59
+ test "isnt keyword", "5 isnt 3", true
60
+ test "isnt keyword false", "5 isnt 5", false
61
+ test "strict inequality triple", "5 !== 3", true
62
+ test "strict inequality false", "5 !== 5", false
63
+
64
+ code "inequality compiles to strict", "a != b", "(a !== b)"
65
+ code "isnt compiles to strict", "a isnt b", "(a !== b)"
66
+ code "triple not-equals compiles to strict", "a !== b", "(a !== b)"
67
+
68
+ # Less than: "<"
69
+ test "less than true", "3 < 5", true
70
+ test "less than false", "5 < 3", false
71
+ code "less than parens", "a < b", "(a < b)"
72
+
73
+ # Greater than: ">"
74
+ test "greater than true", "5 > 3", true
75
+ test "greater than false", "3 > 5", false
76
+ code "greater than parens", "a > b", "(a > b)"
77
+
78
+ # Less than or equal: "<="
79
+ test "less than or equal true", "3 <= 5", true
80
+ test "less than or equal equal", "5 <= 5", true
81
+ code "less than or equal parens", "a <= b", "(a <= b)"
82
+
83
+ # Greater than or equal: ">="
84
+ test "greater than or equal true", "5 >= 3", true
85
+ test "greater than or equal equal", "5 >= 5", true
86
+ code "greater than or equal parens", "a >= b", "(a >= b)"
87
+
88
+ # ============================================================================
89
+ # Logical Operators
90
+ # ============================================================================
91
+
92
+ # Logical NOT: "!"
93
+ test "logical not true", "!false", true
94
+ test "logical not false", "!true", false
95
+ code "logical not simple", "!a", "!a"
96
+ code "logical not complex", "!(a && b)", "(!(a && b))"
97
+
98
+ # Logical AND: "&&"
99
+ test "logical and both true", "true && true", true
100
+ test "logical and first false", "false && true", false
101
+ test "logical and second false", "true && false", false
102
+ code "logical and parens", "a && b", "(a && b)"
103
+
104
+ # Logical OR: "||"
105
+ test "logical or both false", "false || false", false
106
+ test "logical or first true", "true || false", true
107
+ test "logical or second true", "false || true", true
108
+ code "logical or parens", "a || b", "(a || b)"
109
+
110
+ # Nullish coalescing: "??"
111
+ test "nullish with null", "null ?? 10", 10
112
+ test "nullish with undefined", "undefined ?? 20", 20
113
+ test "nullish with zero", "0 ?? 30", 0
114
+ test "nullish with false", "false ?? 40", false
115
+ code "nullish coalescing parens", "a ?? b", "(a ?? b)"
116
+
117
+ # ============================================================================
118
+ # Bitwise Operators
119
+ # ============================================================================
120
+
121
+ # Bitwise AND: "&"
122
+ test "bitwise and", "5 & 3", 1
123
+ code "bitwise and parens", "a & b", "(a & b)"
124
+
125
+ # Bitwise OR: "|"
126
+ test "bitwise or", "5 | 3", 7
127
+ code "bitwise or parens", "a | b", "(a | b)"
128
+
129
+ # Bitwise XOR: "^"
130
+ test "bitwise xor", "5 ^ 3", 6
131
+ code "bitwise xor parens", "a ^ b", "(a ^ b)"
132
+
133
+ # Bitwise NOT: "~"
134
+ test "bitwise not", "~5", -6
135
+ code "bitwise not parens", "~a", "(~a)"
136
+
137
+ # ============================================================================
138
+ # Increment/Decrement: "++" / "--"
139
+ # ============================================================================
140
+
141
+ # Prefix increment: "++"
142
+ test "prefix increment", "x = 5\n++x", 6
143
+
144
+ # Postfix increment: "++"
145
+ test "postfix increment", "x = 5\nx++\nx", 6
146
+
147
+ # Prefix decrement: "--"
148
+ test "prefix decrement", "x = 5\n--x", 4
149
+
150
+ # Postfix decrement: "--"
151
+ test "postfix decrement", "x = 5\nx--\nx", 4
152
+
153
+ # ============================================================================
154
+ # Stats for CODEGEN.md
155
+ # ============================================================================
156
+ # Node types: +, -, *, /, %, **, ==, !=, ===, !==, <, >, <=, >=, &&, ||, ??, !, &, |, ^, ~, <<, >>, >>>, ++, --, //, is, isnt, in, of
157
+ # Tests: 66 total (66 passing, 0 failing)
158
+ # Coverage: Arithmetic, comparison, logical, bitwise, unary, increment/decrement, floor division, identity, membership
@@ -0,0 +1,184 @@
1
+ # Test: Optional and Existence Operators
2
+ # Tests the dual syntax: ? (CoffeeScript soak) vs ?. (ES6 optional chaining)
3
+
4
+ # ============================================================================
5
+ # SINGLE ? - CoffeeScript Soak (Existence-Based)
6
+ # ============================================================================
7
+
8
+ # Postfix existence check: "?"
9
+ # Pattern: expr? → (expr != null)
10
+ test "existence check value", "x = 42\nx?", true
11
+ test "existence check null", "x = null\nx?", false
12
+ test "existence check undefined", "x = undefined\nx?", false
13
+
14
+ # Soak index: "?[]"
15
+ # Pattern: arr?[index] → if (arr != null) arr[index] else undefined
16
+ test "soak index exists", "arr = [1, 2, 3]\narr?[1]", 2
17
+ test "soak index null", "arr = null\narr?[0]", undefined
18
+ test "soak index undefined", "arr = undefined\narr?[5]", undefined
19
+ test "soak index chain", "obj = {arr: [1, 2]}\nobj.arr?[0]", 1
20
+
21
+ # Soak call: fn?(args)
22
+ # Pattern: fn?(arg) → (typeof fn === 'function' ? fn(arg) : undefined)
23
+ test "soak call exists", "fn = (x) -> x * 2\nfn?(5)", 10
24
+ test "soak call null", "fn = null\nfn?(5)", undefined
25
+ test "soak call not function", "fn = 42\nfn?(5)", undefined
26
+
27
+ # Soak with implicit call syntax (works!)
28
+ test "soak call implicit", "fn = (x) -> x * 2\nfn? 5", 10
29
+ test "soak method call", "obj = {fn: (x) -> x}\nobj.fn?(42)", 42
30
+
31
+ # Soak prototype: "?::"
32
+ # Pattern: obj?::method → (obj != null ? obj.prototype.method : undefined)
33
+ test "soak prototype exists", "fn = ->\nfn?::toString", Function.prototype.toString
34
+ test "soak prototype null", "obj = null\nobj?::method", undefined
35
+
36
+ # ============================================================================
37
+ # DOT-BASED ?. - ES6 Optional Chaining (Native Passthrough)
38
+ # ============================================================================
39
+
40
+ # Optional property: "?."
41
+ # Pattern: obj?.prop → obj?.prop (ES6 native)
42
+ test "optional prop exists", "obj = {name: 'test'}\nobj?.name", "test"
43
+ test "optional prop null", "obj = null\nobj?.name", undefined
44
+ test "optional prop undefined", "obj = undefined\nobj?.prop", undefined
45
+ test "optional prop chain", "obj = {nested: {value: 42}}\nobj?.nested?.value", 42
46
+ test "optional prop chain breaks", "obj = {nested: null}\nobj?.nested?.value", undefined
47
+
48
+ # Optional index (ES6): ES6 native optional chaining
49
+ # Pattern: arr?.[index] → arr?.[index] (ES6 native)
50
+ test "es6 optional index exists", "arr = [1, 2, 3]\narr?.[1]", 2
51
+ test "es6 optional index null", "arr = null\narr?.[0]", undefined
52
+ test "es6 optional index chain", "obj = {arr: [1, 2]}\nobj?.arr?.[0]", 1
53
+
54
+ # Optional call (ES6): ES6 native optional chaining
55
+ # Pattern: fn?.(arg) → fn?.(arg) (ES6 native)
56
+ test "es6 optional call exists", "fn = (x) -> x * 2\nfn?.(5)", 10
57
+ test "es6 optional call null", "fn = null\nfn?.(5)", undefined
58
+ test "es6 optional call chain", "obj = {fn: (x) -> x}\nobj?.fn?.(42)", 42
59
+
60
+ # ============================================================================
61
+ # MIXED PATTERNS - Testing Combinations
62
+ # ============================================================================
63
+
64
+ # Soak in expressions
65
+ test "soak with default", "arr = [1, 2]\narr?[0] ?? 99", 1
66
+ test "soak null with default", "arr = null\narr?[0] ?? 99", 99
67
+
68
+ # Optional chaining in expressions
69
+ test "optional with default", "obj = {val: 5}\nobj?.val ?? 10", 5
70
+ test "optional null with default", "obj = null\nobj?.val ?? 10", 10
71
+
72
+ # Nested soaks
73
+ test "nested soak index", "obj = {arr: [1, 2]}\nobj.arr?[0]", 1
74
+ test "nested soak index null", "obj = {arr: null}\nobj.arr?[0]", undefined
75
+
76
+ # ============================================================================
77
+ # EDGE CASES
78
+ # ============================================================================
79
+
80
+ # Soak with expressions
81
+ test "soak index expression", "arr = [10, 20, 30]\ni = 1\narr?[i]", 20
82
+ test "soak index computed", "arr = [1, 2, 3]\narr?[1 + 1]", 3
83
+
84
+ # Optional in assignments
85
+ test "optional assign", "obj = {val: 42}\nx = obj?.val\nx", 42
86
+ test "soak assign", "arr = [1, 2]\nx = arr?[0]\nx", 1
87
+
88
+ # Chaining multiple operators
89
+ test "soak then optional", "obj = {arr: [1, 2]}\nobj.arr?[0]", 1
90
+ test "optional then soak", "obj = {arr: [1, 2]}\nobj?.arr?[0]", 1
91
+
92
+ # ============================================================================
93
+ # CODE GENERATION TESTS
94
+ # ============================================================================
95
+
96
+ # CoffeeScript soak (single ?) - Generates existence checks
97
+ code "soak index gen", "arr?[0]", "(arr != null ? arr[0] : undefined)"
98
+ code "soak call gen", "fn?(42)", "(typeof fn === 'function' ? fn(42) : undefined)"
99
+ code "soak prototype gen", "obj?::method", "(obj != null ? obj.prototype.method : undefined)"
100
+
101
+ # ES6 optional chaining (?.) - Passthrough to native
102
+ code "optional property gen", "obj?.prop", "obj?.prop"
103
+ code "es6 optional index gen", "arr?.[0]", "arr?.[0]"
104
+ code "es6 optional call gen", "fn?.(42)", "fn?.(42)"
105
+
106
+ # Existence check (postfix ?)
107
+ code "existence gen", "x?", "(x != null)"
108
+
109
+ # ============================================================================
110
+ # SEMANTIC NOTES
111
+ # ============================================================================
112
+
113
+ # Dual optional syntax semantics:
114
+ # - ? operators (soak): Compile to existence checks (cross-browser)
115
+ # - ?. operators: Native ES6 optional chaining (modern browsers)
116
+
117
+ # ============================================================================
118
+ # Stats for CODEGEN.md
119
+ # ============================================================================
120
+ # Optional operators implemented: ?[], ?., ?, ?::
121
+ # Soak semantics: Existence-based (CoffeeScript)
122
+ # ES6 semantics: Native optional chaining
123
+ # Tests passing: TBD
124
+ # Test: Existence Check (1 node type)
125
+ # Tests "?" (postfix existence) node type
126
+
127
+ # ============================================================================
128
+ # Existence Check: "?"
129
+ # ============================================================================
130
+
131
+ # Basic existence check
132
+ test "exists check true", "x = 42\nx?", true
133
+ test "exists check null", "x = null\nx?", false
134
+ test "exists check undefined", "x = undefined\nx?", false
135
+
136
+ # Existence in conditional
137
+ test "if exists", "x = 42; if x? then 'exists' else 'missing'", "exists"
138
+ test "if not exists", "x = null; if x? then 'exists' else 'missing'", "missing"
139
+
140
+ # Code generation
141
+ code "existence check", "x?", "(x != null)"
142
+
143
+ # ============================================================================
144
+ # Stats for CODEGEN.md
145
+ # ============================================================================
146
+ # Existence check implemented: 0/1 (0%)
147
+ # Tests passing: 0/5 (0%)
148
+ # Test: Nullish Coalescing with Splats
149
+ # Modern ?? alternative to CoffeeScript's binary ? operator
150
+
151
+ # These tests are Rip-specific, showing how to use ?? (ES2020)
152
+ # instead of CoffeeScript's binary existential ? operator
153
+
154
+ # Splat with nullish coalescing
155
+ test "splat existential with default", '''
156
+ c = null
157
+ [...(c?.b ?? [])]
158
+ ''', []
159
+
160
+ test "splat with value", '''
161
+ c = {b: [1, 2, 3]}
162
+ [...(c?.b ?? [])]
163
+ ''', [1, 2, 3]
164
+
165
+ test "conditional with nullish", '''
166
+ a = {b: [3]}
167
+ f = false
168
+ result = (a if f)?.b ?? []
169
+ result
170
+ ''', []
171
+
172
+ test "trailing if with nullish default", '''
173
+ a = [3]
174
+ c = false
175
+ result = (a if c) ?? []
176
+ result
177
+ ''', []
178
+
179
+ # ============================================================================
180
+ # Stats for CODEGEN.md
181
+ # ============================================================================
182
+ # Node types: ?, ?[], ?(), ?::, ?., ?.[, ?.(, ??, ??=
183
+ # Tests: 54 total (54 passing, 0 failing)
184
+ # Coverage: Dual syntax (CoffeeScript soak + ES6 optional chaining), existence checks, nullish coalescing, soaks