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,94 @@
|
|
|
1
|
+
# Test: Property Access (6 node types)
|
|
2
|
+
# Tests ".", "?.", "::", "?::", "[]", "?[]" node types
|
|
3
|
+
|
|
4
|
+
# ============================================================================
|
|
5
|
+
# Property Access: "."
|
|
6
|
+
# ============================================================================
|
|
7
|
+
|
|
8
|
+
# Basic property access
|
|
9
|
+
test "property access", "obj = {x: 42}; obj.x", 42
|
|
10
|
+
test "nested property", "obj = {a: {b: 10}}; obj.a.b", 10
|
|
11
|
+
test "property chain", "obj = {a: {b: {c: 5}}}; obj.a.b.c", 5
|
|
12
|
+
|
|
13
|
+
# Code generation
|
|
14
|
+
code "property access", "obj.prop", "obj.prop"
|
|
15
|
+
code "chained property", "obj.a.b", "obj.a.b"
|
|
16
|
+
|
|
17
|
+
# Method access
|
|
18
|
+
test "method access", "obj = {fn: -> 42}; obj.fn()", 42
|
|
19
|
+
|
|
20
|
+
# ============================================================================
|
|
21
|
+
# Optional Chaining: "?."
|
|
22
|
+
# ============================================================================
|
|
23
|
+
|
|
24
|
+
# Optional property access
|
|
25
|
+
test "optional chain exists", "obj = {x: 42}; obj?.x", 42
|
|
26
|
+
test "optional chain null", "obj = null; obj?.x", undefined
|
|
27
|
+
test "optional chain undefined", "obj = undefined; obj?.x", undefined
|
|
28
|
+
|
|
29
|
+
# Code generation
|
|
30
|
+
code "optional chain", "obj?.prop", "obj?.prop"
|
|
31
|
+
|
|
32
|
+
# Chained optional access
|
|
33
|
+
test "chained optional", "obj = {a: {b: 10}}; obj?.a?.b", 10
|
|
34
|
+
test "chained optional null", "obj = {a: null}; obj?.a?.b", undefined
|
|
35
|
+
|
|
36
|
+
# ============================================================================
|
|
37
|
+
# Prototype Access: "::"
|
|
38
|
+
# ============================================================================
|
|
39
|
+
|
|
40
|
+
# Direct prototype access
|
|
41
|
+
test "prototype access", "Array::push", Array.prototype.push
|
|
42
|
+
test "prototype method", "Boolean::toString", Boolean.prototype.toString
|
|
43
|
+
|
|
44
|
+
# Code generation
|
|
45
|
+
code "prototype access", "obj::method", "obj.prototype.method"
|
|
46
|
+
|
|
47
|
+
# Shorthand prototype
|
|
48
|
+
test "shorthand prototype", "Array::", Array.prototype
|
|
49
|
+
|
|
50
|
+
# ============================================================================
|
|
51
|
+
# Optional Prototype: "?::"
|
|
52
|
+
# ============================================================================
|
|
53
|
+
|
|
54
|
+
# Optional prototype access
|
|
55
|
+
test "optional prototype exists", "Array?::push", Array.prototype.push
|
|
56
|
+
test "optional prototype null", "obj = null; obj?::method", undefined
|
|
57
|
+
|
|
58
|
+
# Code generation
|
|
59
|
+
code "optional prototype", "obj?::method", "(obj != null ? obj.prototype.method : undefined)"
|
|
60
|
+
|
|
61
|
+
# ============================================================================
|
|
62
|
+
# Array Indexing: "[]"
|
|
63
|
+
# ============================================================================
|
|
64
|
+
|
|
65
|
+
# Basic indexing
|
|
66
|
+
test "array index", "arr = [10, 20, 30]; arr[1]", 20
|
|
67
|
+
test "negative index", "arr = [1, 2, 3]; arr[arr.length - 1]", 3
|
|
68
|
+
test "index expression", "arr = [10, 20]; i = 1; arr[i]", 20
|
|
69
|
+
|
|
70
|
+
# Code generation
|
|
71
|
+
code "array index", "arr[0]", "arr[0]"
|
|
72
|
+
code "index expression", "arr[i + 1]", "arr[(i + 1)]"
|
|
73
|
+
|
|
74
|
+
# Object bracket notation
|
|
75
|
+
test "object bracket", 'obj = {name: "test"}; obj["name"]', "test"
|
|
76
|
+
test "dynamic property", 'obj = {x: 42}; key = "x"; obj[key]', 42
|
|
77
|
+
|
|
78
|
+
# ============================================================================
|
|
79
|
+
# Optional Indexing: "?[]"
|
|
80
|
+
# ============================================================================
|
|
81
|
+
|
|
82
|
+
# Optional array indexing (ES6)
|
|
83
|
+
test "optional index exists", "arr = [1, 2, 3]\narr?.[1]", 2
|
|
84
|
+
test "optional index null", "arr = null\narr?.[0]", undefined
|
|
85
|
+
|
|
86
|
+
# Code generation
|
|
87
|
+
code "optional index", "arr?.[i]", "arr?.[i]"
|
|
88
|
+
|
|
89
|
+
# ============================================================================
|
|
90
|
+
# Stats for CODEGEN.md
|
|
91
|
+
# ============================================================================
|
|
92
|
+
# Node types: ., [], ::, ?., ?.[, ?::
|
|
93
|
+
# Tests: 29 total (29 passing, 0 failing)
|
|
94
|
+
# Coverage: Property access, array indexing, prototype access, optional chaining, dynamic properties, nested access
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Test: Regular Expressions (1 node type)
|
|
2
|
+
# Tests "regex" node type
|
|
3
|
+
|
|
4
|
+
# ============================================================================
|
|
5
|
+
# Regular Expression Literals: "regex"
|
|
6
|
+
# ============================================================================
|
|
7
|
+
|
|
8
|
+
# Basic regex
|
|
9
|
+
test "regex literal test", '/hello/.test("hello world")', true
|
|
10
|
+
test "regex literal no match", '/goodbye/.test("hello world")', false
|
|
11
|
+
|
|
12
|
+
# Regex with flags
|
|
13
|
+
test "regex with i flag", '/HELLO/i.test("hello")', true
|
|
14
|
+
test "regex with g flag", '"aaa".match(/a/g).length', 3
|
|
15
|
+
|
|
16
|
+
# Code generation
|
|
17
|
+
code "regex literal", "/test/", "/test/"
|
|
18
|
+
code "regex with flags", "/test/gi", "/test/gi"
|
|
19
|
+
|
|
20
|
+
# Regex methods
|
|
21
|
+
test "regex exec", '/world/.exec("hello world")[0]', "world"
|
|
22
|
+
test "string match", '"test123".match(/\\d+/)[0]', "123"
|
|
23
|
+
|
|
24
|
+
# ============================================================================
|
|
25
|
+
# Stats for CODEGEN.md
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# Regex implemented: 0/1 (0%)
|
|
28
|
+
# Tests passing: 0/8 (0%)
|
|
29
|
+
|
|
30
|
+
# Test: Regex Features (=~ and regex indexing)
|
|
31
|
+
# Tests Ruby-style regex matching with automatic _ variable capture
|
|
32
|
+
|
|
33
|
+
# ============================================================================
|
|
34
|
+
# =~ Operator (Regex Match with _ capture)
|
|
35
|
+
# ============================================================================
|
|
36
|
+
|
|
37
|
+
# Basic regex match
|
|
38
|
+
test '=~ basic match', '''
|
|
39
|
+
text = 'hello world'
|
|
40
|
+
result = text =~ /world/
|
|
41
|
+
result[0]
|
|
42
|
+
''', 'world'
|
|
43
|
+
|
|
44
|
+
# Capture groups with _
|
|
45
|
+
test '=~ capture groups', '''
|
|
46
|
+
text = 'hello world'
|
|
47
|
+
text =~ /(\\w+) (\\w+)/
|
|
48
|
+
_[1]
|
|
49
|
+
''', 'hello'
|
|
50
|
+
|
|
51
|
+
# Multiple captures
|
|
52
|
+
test '=~ multiple captures', '''
|
|
53
|
+
text = 'hello world'
|
|
54
|
+
text =~ /(\\w+) (\\w+)/
|
|
55
|
+
_[2]
|
|
56
|
+
''', 'world'
|
|
57
|
+
|
|
58
|
+
# No match returns null
|
|
59
|
+
test '=~ no match', '''
|
|
60
|
+
text = 'hello'
|
|
61
|
+
result = text =~ /xyz/
|
|
62
|
+
result
|
|
63
|
+
''', null
|
|
64
|
+
|
|
65
|
+
# Match at start
|
|
66
|
+
test '=~ match at start', '''
|
|
67
|
+
text = 'hello world'
|
|
68
|
+
text =~ /^(\\w+)/
|
|
69
|
+
_[1]
|
|
70
|
+
''', 'hello'
|
|
71
|
+
|
|
72
|
+
# Match at end
|
|
73
|
+
test '=~ match at end', '''
|
|
74
|
+
text = 'hello world'
|
|
75
|
+
text =~ /(\\w+)$/
|
|
76
|
+
_[1]
|
|
77
|
+
''', 'world'
|
|
78
|
+
|
|
79
|
+
# With flags
|
|
80
|
+
test '=~ case insensitive', '''
|
|
81
|
+
text = 'HELLO'
|
|
82
|
+
text =~ /hello/i
|
|
83
|
+
_[0]
|
|
84
|
+
''', 'HELLO'
|
|
85
|
+
|
|
86
|
+
# Global flag (returns first match, sets _)
|
|
87
|
+
test '=~ global flag', '''
|
|
88
|
+
text = 'foo bar foo'
|
|
89
|
+
text =~ /foo/g
|
|
90
|
+
_[0]
|
|
91
|
+
''', 'foo'
|
|
92
|
+
|
|
93
|
+
# Works with numbers (via toSearchable)
|
|
94
|
+
test '=~ with number', '''
|
|
95
|
+
num = 12345
|
|
96
|
+
num =~ /(\\d{3})/
|
|
97
|
+
_[1]
|
|
98
|
+
''', '123'
|
|
99
|
+
|
|
100
|
+
# Works with null (converts to empty string)
|
|
101
|
+
test '=~ with null', '''
|
|
102
|
+
x = null
|
|
103
|
+
result = x =~ /test/
|
|
104
|
+
result
|
|
105
|
+
''', null
|
|
106
|
+
|
|
107
|
+
# Email parsing example
|
|
108
|
+
test '=~ email parsing', '''
|
|
109
|
+
email = 'user@example.com'
|
|
110
|
+
email =~ /(.+)@(.+)/
|
|
111
|
+
_[2]
|
|
112
|
+
''', 'example.com'
|
|
113
|
+
|
|
114
|
+
# ============================================================================
|
|
115
|
+
# Regex Indexing (value[/pattern/] and value[/pattern/, n])
|
|
116
|
+
# ============================================================================
|
|
117
|
+
|
|
118
|
+
# Simple regex indexing (returns full match)
|
|
119
|
+
test 'regex index simple', '"steve"[/eve/]', 'eve'
|
|
120
|
+
|
|
121
|
+
# Regex indexing with capture group
|
|
122
|
+
test 'regex index capture', '"steve"[/e(v)e/, 1]', 'v'
|
|
123
|
+
|
|
124
|
+
# Multiple capture groups
|
|
125
|
+
test 'regex index multiple captures', '''
|
|
126
|
+
text = 'hello world'
|
|
127
|
+
text[/(\\w+) (\\w+)/, 2]
|
|
128
|
+
''', 'world'
|
|
129
|
+
|
|
130
|
+
# No match returns null
|
|
131
|
+
test 'regex index no match', '"hello"[/xyz/]', null
|
|
132
|
+
|
|
133
|
+
# Works with numbers
|
|
134
|
+
test 'regex index number', '''
|
|
135
|
+
num = 12345
|
|
136
|
+
num[/\\d{3}/]
|
|
137
|
+
''', '123'
|
|
138
|
+
|
|
139
|
+
# Email domain extraction
|
|
140
|
+
test 'regex index email domain', '''
|
|
141
|
+
email = 'user@example.com'
|
|
142
|
+
email[/@(.+)$/, 1]
|
|
143
|
+
''', 'example.com'
|
|
144
|
+
|
|
145
|
+
# Phone parsing
|
|
146
|
+
test 'regex index phone', '''
|
|
147
|
+
phone = '(555) 123-4567'
|
|
148
|
+
phone[/\\((\\d{3})\\) (\\d{3})-(\\d{4})/, 2]
|
|
149
|
+
''', '123'
|
|
150
|
+
|
|
151
|
+
# URL parsing
|
|
152
|
+
test 'regex index url', '''
|
|
153
|
+
url = 'https://example.com/path'
|
|
154
|
+
url[/:\\/\\/(\\w+\\.\\w+)/, 1]
|
|
155
|
+
''', 'example.com'
|
|
156
|
+
|
|
157
|
+
# Case insensitive
|
|
158
|
+
test 'regex index case insensitive', '"HELLO"[/hello/i]', 'HELLO'
|
|
159
|
+
|
|
160
|
+
# With anchors (full match required, can't extract partial)
|
|
161
|
+
test 'regex index anchored', '"test123"[/^(test)(\\d+)$/, 1]', 'test'
|
|
162
|
+
|
|
163
|
+
# Nested groups
|
|
164
|
+
test 'regex index nested groups', '''
|
|
165
|
+
text = 'abc123xyz'
|
|
166
|
+
text[/([a-z]+)(\\d+)/, 2]
|
|
167
|
+
''', '123'
|
|
168
|
+
|
|
169
|
+
# ============================================================================
|
|
170
|
+
# Combined Usage (=~ then _ access)
|
|
171
|
+
# ============================================================================
|
|
172
|
+
|
|
173
|
+
# Use =~ then access _ directly
|
|
174
|
+
test 'combined =~ and _', '''
|
|
175
|
+
text = 'hello world'
|
|
176
|
+
if text =~ /(\\w+) (\\w+)/
|
|
177
|
+
_[1] + '-' + _[2]
|
|
178
|
+
else
|
|
179
|
+
'no match'
|
|
180
|
+
''', 'hello-world'
|
|
181
|
+
|
|
182
|
+
# Chain multiple regex operations
|
|
183
|
+
test 'chained regex ops', '''
|
|
184
|
+
email = 'admin@company.com'
|
|
185
|
+
if email =~ /(.+)@(.+)/
|
|
186
|
+
domain = _[2]
|
|
187
|
+
domain[/(\\w+)\\./, 1]
|
|
188
|
+
else
|
|
189
|
+
null
|
|
190
|
+
''', 'company'
|
|
191
|
+
|
|
192
|
+
# Regex in conditionals
|
|
193
|
+
test 'regex in conditional', '''
|
|
194
|
+
text = 'user@example.com'
|
|
195
|
+
result = if text =~ /@/
|
|
196
|
+
'has @'
|
|
197
|
+
else
|
|
198
|
+
'no @'
|
|
199
|
+
result
|
|
200
|
+
''', 'has @'
|
|
201
|
+
|
|
202
|
+
# ============================================================================
|
|
203
|
+
# Validator Pattern Examples (from your code)
|
|
204
|
+
# ============================================================================
|
|
205
|
+
|
|
206
|
+
# ID validator pattern
|
|
207
|
+
test 'validator id pattern', '''
|
|
208
|
+
validate = (v) -> v[/^([1-9]\\d{0,19})$/] and parseInt(_[1])
|
|
209
|
+
validate('12345')
|
|
210
|
+
''', 12345
|
|
211
|
+
|
|
212
|
+
# Email validator pattern
|
|
213
|
+
test 'validator email pattern', '''
|
|
214
|
+
validate = (v) -> v[/^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})$/] and _[0]
|
|
215
|
+
validate('test@example.com')
|
|
216
|
+
''', 'test@example.com'
|
|
217
|
+
|
|
218
|
+
# Zip code extractor
|
|
219
|
+
test 'validator zip pattern', '''
|
|
220
|
+
validate = (v) -> v[/^(\\d{5})/] and _[1]
|
|
221
|
+
validate('12345-6789')
|
|
222
|
+
''', '12345'
|
|
223
|
+
|
|
224
|
+
# Boolean validator with =~
|
|
225
|
+
test 'validator truthy pattern', '''
|
|
226
|
+
validate = (v) -> (v =~ /^(true|t|1|yes|y|on)$/i) and true
|
|
227
|
+
validate('YES')
|
|
228
|
+
''', true
|
|
229
|
+
|
|
230
|
+
# Phone formatter pattern
|
|
231
|
+
test 'validator phone pattern', '''
|
|
232
|
+
num = '2125551234'
|
|
233
|
+
if num =~ /^([2-9][0-8][0-9])([2-9]\\d\\d)(\\d{4})$/
|
|
234
|
+
"(#{_[1]}) #{_[2]}-#{_[3]}"
|
|
235
|
+
else
|
|
236
|
+
null
|
|
237
|
+
''', '(212) 555-1234'
|
|
238
|
+
|
|
239
|
+
# ============================================================================
|
|
240
|
+
# Edge Cases
|
|
241
|
+
# ============================================================================
|
|
242
|
+
|
|
243
|
+
# Empty string
|
|
244
|
+
test 'regex index empty string', '""[/test/]', null
|
|
245
|
+
|
|
246
|
+
# Null value (converts to empty string)
|
|
247
|
+
test 'regex match null', '''
|
|
248
|
+
x = null
|
|
249
|
+
x =~ /test/
|
|
250
|
+
''', null
|
|
251
|
+
|
|
252
|
+
# Array (joins with comma)
|
|
253
|
+
test 'regex match array', '''
|
|
254
|
+
arr = ['hello', 'world']
|
|
255
|
+
arr =~ /hello/
|
|
256
|
+
_[0]
|
|
257
|
+
''', 'hello'
|
|
258
|
+
|
|
259
|
+
# Boolean (converts to string)
|
|
260
|
+
test 'regex match boolean', '''
|
|
261
|
+
x = true
|
|
262
|
+
x =~ /true/
|
|
263
|
+
_[0]
|
|
264
|
+
''', 'true'
|
|
265
|
+
|
|
266
|
+
# Out of range capture index returns undefined
|
|
267
|
+
test 'regex index out of range', '''
|
|
268
|
+
x = "test"[/test/, 5]
|
|
269
|
+
x
|
|
270
|
+
''', undefined
|
|
271
|
+
|
|
272
|
+
# ============================================================================
|
|
273
|
+
# Heregex Interpolation Behavior
|
|
274
|
+
# ============================================================================
|
|
275
|
+
|
|
276
|
+
# IMPORTANT DISTINCTION:
|
|
277
|
+
# - Strings: Both #{...} and ${...} interpolate
|
|
278
|
+
# - Heregex: Only #{...} interpolates, ${...} stays literal (for regex patterns)
|
|
279
|
+
|
|
280
|
+
# #{...} interpolation works in heregex (CoffeeScript style)
|
|
281
|
+
test "heregex #{} interpolation", '''
|
|
282
|
+
name = "world"
|
|
283
|
+
pattern = ///hello#{name}///
|
|
284
|
+
pattern.test("helloworld")
|
|
285
|
+
''', true
|
|
286
|
+
|
|
287
|
+
# ${...} does NOT interpolate in heregex - stays as literal regex pattern (no escape needed!)
|
|
288
|
+
code "heregex ${} no interpolation", '///test${var}end///', '/test${var}end/'
|
|
289
|
+
|
|
290
|
+
# $ anchor works correctly in heregex
|
|
291
|
+
test "heregex $ anchor", '''
|
|
292
|
+
pattern = ///^test$///
|
|
293
|
+
pattern.test("test") and not pattern.test("testing")
|
|
294
|
+
''', true
|
|
295
|
+
|
|
296
|
+
# ============================================================================
|
|
297
|
+
# Stats for CODEGEN.md
|
|
298
|
+
# ============================================================================
|
|
299
|
+
# Node types: regex (literals, heregex)
|
|
300
|
+
# Tests: 46 total (46 passing, 0 failing)
|
|
301
|
+
# Coverage: Regex literals, flags, heregex (extended), =~ operator, regex indexing, validators, edge cases, interpolation behavior
|