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.
- package/.cursor/rules/rip-agent-onboarding.md +681 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +98 -0
- package/.github/ISSUE_TEMPLATE/coffeescript_compatibility.yml +86 -0
- package/.github/ISSUE_TEMPLATE/config.yml +9 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +82 -0
- package/.github/ISSUE_TEMPLATE/question.yml +55 -0
- package/.github/pull_request_template.md +84 -0
- package/AGENT.md +623 -0
- package/CONTRIBUTING.md +331 -0
- package/LICENSE +21 -0
- package/README.md +1245 -0
- package/SETUP.md +144 -0
- package/bar.coffee +394 -0
- package/bin/rip +162 -0
- package/bunfig.toml +11 -0
- package/docs/BROWSER.md +983 -0
- package/docs/CODEGEN.md +1023 -0
- package/docs/COFFEESCRIPT-COMPARISON.md +740 -0
- package/docs/COMPREHENSIONS.md +572 -0
- package/docs/REGEX-PLUS.md +441 -0
- package/docs/SOLAR.md +846 -0
- package/docs/SPECIAL-OPERATORS.md +769 -0
- package/docs/STRING.md +363 -0
- package/docs/WHY-NOT-COFFEESCRIPT.md +184 -0
- package/docs/WHY-YES-RIP.md +690 -0
- package/docs/WORKFLOW.md +306 -0
- package/docs/dist/rip.browser.js +6798 -0
- package/docs/dist/rip.browser.min.js +242 -0
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/example.html +177 -0
- package/docs/examples/README.md +154 -0
- package/docs/examples/arrows.rip +84 -0
- package/docs/examples/async-await.rip +59 -0
- package/docs/examples/existential.rip +86 -0
- package/docs/examples/fibonacci.rip +12 -0
- package/docs/examples/module.rip +38 -0
- package/docs/examples/object-syntax.rip +74 -0
- package/docs/examples/prototype.rip +30 -0
- package/docs/examples/ranges.rip +45 -0
- package/docs/examples/switch.rip +50 -0
- package/docs/examples/ternary.rip +36 -0
- package/docs/examples/use-loader.js +9 -0
- package/docs/examples/utils.rip +20 -0
- package/docs/index.html +65 -0
- package/docs/repl.html +914 -0
- package/docs/rip-1280w.png +0 -0
- package/docs/rip.svg +4 -0
- package/package.json +52 -0
- package/rip-loader.ts +27 -0
- package/scripts/build-browser.js +76 -0
- package/scripts/serve.js +71 -0
- package/src/browser.js +97 -0
- package/src/codegen.js +4808 -0
- package/src/compiler.js +270 -0
- package/src/grammar/grammar.rip +801 -0
- package/src/grammar/solar.rip +1056 -0
- package/src/lexer.js +3145 -0
- package/src/parser.js +352 -0
- package/src/repl.js +423 -0
- package/test/rip/assignment.rip +115 -0
- package/test/rip/async.rip +361 -0
- package/test/rip/basic.rip +171 -0
- package/test/rip/classes.rip +167 -0
- package/test/rip/compatibility.rip +338 -0
- package/test/rip/comprehensions.rip +104 -0
- package/test/rip/control.rip +177 -0
- package/test/rip/data.rip +215 -0
- package/test/rip/errors.rip +129 -0
- package/test/rip/functions.rip +443 -0
- package/test/rip/guards.rip +247 -0
- package/test/rip/literals.rip +131 -0
- package/test/rip/loops.rip +117 -0
- package/test/rip/modules.rip +87 -0
- package/test/rip/operators.rip +158 -0
- package/test/rip/optional.rip +184 -0
- package/test/rip/properties.rip +94 -0
- package/test/rip/regex.rip +301 -0
- package/test/rip/stabilization.rip +825 -0
- package/test/rip/strings.rip +483 -0
- 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
|