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
package/SETUP.md ADDED
@@ -0,0 +1,144 @@
1
+ # Rip Global Setup Guide
2
+
3
+ Quick guide to set up Rip so `.rip` files work anywhere with Bun.
4
+
5
+ ## One-Time Setup (5 minutes)
6
+
7
+ ```bash
8
+ # 1. Clone Rip
9
+ git clone https://github.com/yourusername/rip.git
10
+ cd rip
11
+
12
+ # 2. Link globally
13
+ bun link
14
+
15
+ # 3. Configure Bun to auto-load Rip
16
+ echo 'preload = ["rip-lang/loader"]' >> ~/.bunfig.toml
17
+
18
+ # 4. Verify
19
+ bun pm ls --global | grep rip-lang
20
+ cat ~/.bunfig.toml
21
+ ```
22
+
23
+ ## Test It Works
24
+
25
+ ```bash
26
+ # Go anywhere
27
+ cd ~
28
+
29
+ # Create a test file
30
+ cat > hello.rip << 'EOF'
31
+ def greet(name)
32
+ "Hello, ${name}!"
33
+
34
+ console.log greet("World")
35
+ EOF
36
+
37
+ # Run it
38
+ bun hello.rip
39
+ # → Hello, World!
40
+ ```
41
+
42
+ ## How It Works
43
+
44
+ 1. **`bun link`** - Makes the `rip-lang` package available globally
45
+ 2. **`~/.bunfig.toml`** - Tells Bun to preload the Rip loader for all projects
46
+ 3. **Automatic compilation** - When you run `bun script.rip`, the loader compiles it on-the-fly
47
+
48
+ ## Using in Projects
49
+
50
+ ### Import .rip modules
51
+
52
+ ```rip
53
+ # utils.rip
54
+ export def add(a, b)
55
+ a + b
56
+
57
+ export multiply = (a, b) => a * b
58
+ ```
59
+
60
+ ```rip
61
+ # main.rip
62
+ import { add, multiply } from "./utils.rip"
63
+
64
+ console.log add(5, 3) # 8
65
+ console.log multiply(4, 7) # 28
66
+ ```
67
+
68
+ ```bash
69
+ bun main.rip # Works!
70
+ ```
71
+
72
+ ### Per-project override
73
+
74
+ If you want project-specific configuration:
75
+
76
+ ```bash
77
+ # In your project directory
78
+ echo 'preload = ["rip-lang/loader"]' > bunfig.toml
79
+
80
+ # Now this project uses Rip
81
+ bun your-script.rip
82
+ ```
83
+
84
+ ## Uninstalling
85
+
86
+ ```bash
87
+ # Remove global link
88
+ bun unlink rip-lang
89
+
90
+ # Remove from global config
91
+ sed -i.bak '/rip-lang/d' ~/.bunfig.toml
92
+ ```
93
+
94
+ ## Troubleshooting
95
+
96
+ ### "Cannot find package rip-lang"
97
+
98
+ The package isn't linked. Run:
99
+ ```bash
100
+ cd /path/to/rip-lang
101
+ bun link
102
+ ```
103
+
104
+ ### Imports not working
105
+
106
+ Make sure you include the `.rip` extension:
107
+ ```rip
108
+ import { fn } from "./utils.rip" # ✅ Good
109
+ import { fn } from "./utils" # ❌ Bad
110
+ ```
111
+
112
+ ### Changes not reflecting
113
+
114
+ Bun might be caching. Try:
115
+ ```bash
116
+ bun --bun script.rip # Bypass cache
117
+ ```
118
+
119
+ ## What Gets Installed
120
+
121
+ **Global:**
122
+ - Link to `rip-lang` package (via `bun link`)
123
+ - One line in `~/.bunfig.toml`
124
+
125
+ **Nothing else!** Rip has zero dependencies.
126
+
127
+ ## Future: NPM Package
128
+
129
+ Once Rip is published to npm:
130
+
131
+ ```bash
132
+ # Install globally
133
+ bun add -g rip-lang
134
+
135
+ # Or per-project
136
+ bun add -d rip-lang
137
+
138
+ # Same config
139
+ echo 'preload = ["rip-lang/loader"]' > bunfig.toml
140
+ ```
141
+
142
+ ---
143
+
144
+ **Questions?** See [README.md](README.md) for complete documentation.
package/bar.coffee ADDED
@@ -0,0 +1,394 @@
1
+ #!/usr/bin/env coffee
2
+
3
+ # =============================================================================
4
+ # bar.coffee: HL7-like message payload processing library
5
+ #
6
+ # Author: Steve Shreeve <steve.shreeve@ariselab.com>
7
+ # Legal: Copyright (C) 2017, Arise Lab. All rights reserved.
8
+ # =============================================================================
9
+
10
+ PDF417 = require './pdf-417'
11
+
12
+ type = (obj) -> if obj? then (obj.constructor?.name or Object::toString.call(obj)[8...-1]).toLowerCase() else String(obj)
13
+
14
+ get = (str, one, two) ->
15
+ len = if +one > 0 then +one else if +two > 0 then +two else 0
16
+ alt = if two >= '' then two else ''
17
+ if str then (if len and str.length > len then str[0...len] else str) else alt
18
+
19
+ time = (len=14) ->
20
+ str = new Date().toISOString()
21
+ str = [str[0..3], str[5..6], str[8..9], str[11..12], str[14..15], str[17..18]].join('')
22
+ str[0...len]
23
+
24
+ class Bar
25
+ constructor: (obj...) ->
26
+ obj = obj[0] if obj.length < 2
27
+ who = type(obj)
28
+
29
+ # delimiters
30
+ [@fld, @rep, @com, @str] = "|~^".split('')
31
+
32
+ # initialize (newer spec)
33
+ # @str = """
34
+ # H||||^^||
35
+ # P|||||||||^^|||||||||||^^|||||||||^^|||||||^|||||||||^|||||||||^^^^^^^^^^^^^^|^^^^^^^|||||||||||||||||^^|^^|^^|^^||||^||||||^^|^^^^|||^||||
36
+ # C|||||||||||||||||||^||||||||
37
+ # A|||||||||||||||||||||^^|^|^||||||^^|^^^^^|||^^^||
38
+ # M||||||
39
+ # T|||||||||||||||||||||||||||||||||||||||||
40
+ # S|^^^^^^|
41
+ # G||^|||
42
+ # D|||
43
+ # L||
44
+ # E||
45
+ # """
46
+
47
+ # initialize (older spec for Edifecs)
48
+ @str = """
49
+ H||||^^||
50
+ P|||||||||^^|||||||||||^^|||||||||^^|||||||^|||||||||^|||||||||^^^^^^^^^^^^^^|^^^^^^^|||||||||||||||||^^|^^|^^|^^||||^||||||^^|^^^^|||^||
51
+ C|||||||||||||||||||^||||||||
52
+ A|||||||||||||||||||||^^|^|^||||||^^|^^^^^|||
53
+ M||||||
54
+ T|||||||||||||||||||||||||||||||||||||||||
55
+ S|^^^^^^|
56
+ D|||
57
+ L||
58
+ E||
59
+ """
60
+ @ary = @to_a(@str)
61
+
62
+ # load message
63
+ if obj then switch who
64
+ when 'string' then @set(obj)
65
+ when 'array' then @data(obj)
66
+ when 'object' then @data(obj)
67
+ else throw "unable to create Bar objects from #{who} objects"
68
+
69
+ to_a: (str) -> @ary = str.trim().split(/[\r\n]+/).map((str) => str.trim().split(@fld)) # force parse
70
+ to_s: (eol) -> @str = @ary.map((row) => row.join(@fld)).join(eol or "\r") # force build
71
+ scan: (rgx, str = @str or @to_s()) ->
72
+ ary = []
73
+ str.replace rgx, (use, arg..., idx, all) ->
74
+ len = arg.length
75
+ ary.push(if len > 1 then arg else if len is 1 then arg[0] else use)
76
+ use
77
+ ary
78
+ make: (seg) -> [seg.toUpperCase(), '']
79
+
80
+ # ┌──────────────┬─────┬────┬─────┬─────┬─────┬───────────────────┬───┐
81
+ # │ seg.fld(rep) │ rgx │rep │ get │ set │ ary │ notes │ # │
82
+ # ╞══════════════╪═════╪════╪═════╪═════╪═════╪═══════════════════╪═══╡
83
+ # │ seg.fld-5 │ und │ 1 │ beg │ end │ │ beg/end or append │ 1 │
84
+ # │ seg.fld(0)-5 │ '0' │ 0 │ beg │ pre │ │ pre fld or append │ 5 │
85
+ # │ seg.fld(+)-5 │ '+' │ + │ end │ aft │ │ always append │ 4 │
86
+ # ├──────────────┼─────┼────┼─────┼─────┼─────┼───────────────────┼───┤
87
+ # │ seg.fld(2)-5 │ '2' │ 2 │ idx │ idx │ yes │ idx or append │ 3 │
88
+ # │ seg.fld()-5 │ '' │-1 │ end │ end │ yes │ last or append │ 2 │
89
+ # ├──────────────┼─────┼────┼─────┼─────┼─────┼───────────────────┼───┤
90
+ # │ seg.fld(?)-5 │ '?' │ ? │ ask │ all │ yes │ set all │ 6 │
91
+ # └──────────────┴─────┴────┴─────┴─────┴─────┴───────────────────┴───┘
92
+
93
+ data: (pos, val) ->
94
+ # console.log ["data:", arguments.length, Array.apply(null, arguments)]
95
+ switch cnt = arguments.length
96
+ when 0 then return @str or @to_s()
97
+ when 1 then switch type(obj = pos)
98
+ when 'array' then @data(obj[i], obj[i+1]) for i in [0...obj.length] by 2; return @
99
+ when 'object' then @data(key, val) for key, val of obj ; return @
100
+ when 'string' then return @set(obj) if /\s/.test(obj)
101
+ when 2 then if val in [undefined, null, false] then return @
102
+ else
103
+ obj = Array.apply(null, arguments)
104
+ len = obj.length
105
+ @data(obj[i], obj[i+1]) for i in [0...(len - 1)] by 2
106
+ return if len % 2 then @data(obj[len - 1]) else @
107
+
108
+ rgx = ///^ # String 'H.1(2)-3'
109
+ ([HPCAMBKITSGDLE]) # 1: seg 'H'
110
+ [-.]?([1-9]\d*)? # 2: fld '1'
111
+ (?:\(([?+]|\d*)\))? # 3: rep '2'
112
+ [-.]?([1-9]\d*)? # 4: com '3'
113
+ (?:\[(\d+)\])? # 5: chr (set character position when "Y")
114
+ (?:\=(.+))? # 6: hcv (set hard coded value when "Y")
115
+ $///i.exec(pos) or throw "invalid access: #{pos}"
116
+
117
+ seg = rgx[1]
118
+ fld = +rgx[2] if rgx[2]?
119
+ rep = rgx[3]; rep and '+?'.includes(rep) or rep = +rep or if rep>='' then rep.length - 1 else if cnt is 1 then null else -1
120
+ com = +rgx[4] if rgx[4]?
121
+ chr = +rgx[5] if rgx[5]?
122
+ hcv = rgx[6]
123
+
124
+ if cnt is 1 # get
125
+ regx = new RegExp("^#{seg}.*", "igm")
126
+
127
+ return '' unless out = @scan(regx)[0 ] # get first one
128
+ return '' unless out = out.split(@fld)[fld ] if fld
129
+ return '' if -1< out = out.split(@rep).length if rep is '?'
130
+ return '' unless out = out.split(@rep)[rep - 1] if rep or (com and (rep or= 1))
131
+ return '' unless out = out.split(@com)[com - 1] if com
132
+ out
133
+
134
+ else # set
135
+ # console.log ["data:", arguments.length, Array.apply(null, arguments)]
136
+
137
+ @str = null # invalidate @str on set
138
+ regx = new RegExp("^#{seg}", "i")
139
+
140
+ # adjust arrays
141
+ unless ~(idx = @ary.findIndex (row) -> regx.test row[0])
142
+ idx = @ary.push(@make seg) - 1 # append
143
+ row = @ary[idx]
144
+
145
+ # adjust value (we could do custom transforms here)
146
+ val = if val? then "#{val}" else ""
147
+ yep = val.toUpperCase() is "Y" if hcv or chr
148
+ val = hcv if hcv and yep
149
+
150
+ unless fld? # set whole segment
151
+ row[1..] = val.split(@fld)
152
+ else # set field
153
+
154
+ # allow values to span multiple fields
155
+ [val, etc...] = val.split(@fld)
156
+
157
+ unless (had = row[fld] or "") # no prior value
158
+ had += @rep for [1...rep] by 1 if rep and rep > 1
159
+ had += @com for [1...com] by 1 if com and com > 1
160
+ val = 1 if val is ':rep' # auto-count
161
+ val = @chr_set(chr, yep) if chr
162
+ val = had + val
163
+ else # existing value
164
+
165
+ # repeat logic: fld(rep) is analogous to seg(num)
166
+ our = had.split(@rep)
167
+ len = our.length
168
+ if rep in [1,0,'+']
169
+ if rep >= 0 and len > (idx = 0)
170
+ rep or our.unshift('') # pre fld
171
+ else idx = our.push('') - 1 # append
172
+ else # idx, last, '?'
173
+ if +rep # idx, last
174
+ rep += (len or 1) + 1 if rep < 0 # last
175
+ our.push('') for [len...rep] by 1 if rep > len # grow
176
+ idx = rep - 1
177
+ if rep>=0 or rep is '+'
178
+ val = our.length if val is ':rep' # auto-count
179
+ else throw "setting by '?' is not yet implemented"
180
+
181
+ # assemble value
182
+ unless com
183
+ val = @chr_set(chr, yep, our[idx]) if chr
184
+ our[idx] = val
185
+ else
186
+ one = our[idx].split(@com)
187
+ val = @chr_set(chr, yep, our[com - 1]) if chr
188
+ one[com - 1] = val
189
+ our[idx] = one.join(@com)
190
+ val = our.join(@rep)
191
+
192
+ # set field value(s)
193
+ row.push('') for [row.length...fld] if fld > row.length
194
+ row[fld..(fld+etc.length)] = [val, etc...]
195
+
196
+ @ # return self
197
+
198
+ chr_set: (chr, yep, val) ->
199
+ ary = (val or '').split ''
200
+ ary[chr - 1] = if yep then 'Y' else ' '
201
+ val = (now or ' ' for now in ary).join('').replace(/\s+$/, '')
202
+
203
+ set: (str) ->
204
+
205
+ # handy regexes
206
+ enc = [ /^\s*[A-Z]\|/im , /^\s*([^#][^\r\n]*)/gm ]
207
+ tpl = [ /^\s*[A-Z][-.]\d+/im, /^\s*([^\s#]+)\s+([^\r\n]*)/igm ]
208
+
209
+ switch
210
+ when enc[0].test str # encoded string
211
+ for row in @scan enc[1], str
212
+ [seg, col...] = row.split(@fld)
213
+ for fld, nfld in col
214
+ for rep, nrep in fld.split(@rep)
215
+ all = rep.split(@com)
216
+ mas = all.length > 1
217
+ for com, ncom in all when com # skip falsy values
218
+ tag = "#{seg.toLowerCase()}.#{nfld + 1}"
219
+ tag += "(#{nrep + 1})" if nrep > 0
220
+ tag += "-#{ncom + 1}" if mas
221
+ # p [tag, com]
222
+ @data(tag, com)
223
+ when tpl[0].test str # templated string
224
+ @data(pair...) for pair in @scan tpl[1], str when pair[1] # skip falsy values
225
+ else throw "unable to import invalid string"
226
+
227
+ @ # return self
228
+
229
+ to_png: ->
230
+ png = new PDF417( @inspect()).to_png()
231
+ png.exp = new PDF417(@exp.inspect()).to_png() if @exp
232
+ png.over = true if @over
233
+ png
234
+
235
+ to_svg: -> new PDF417(@inspect()).to_svg()
236
+
237
+ inspect: -> @to_s().toUpperCase()
238
+
239
+ show: ->
240
+ pad = (new Array(9+1)).join ' '
241
+ rgx = RegExp "[^#{@com}]"
242
+ for [seg, row...] in @ary
243
+ for fld, i in row when fld > '' and rgx.test fld
244
+ all = fld.split @rep
245
+ for rep, j in all
246
+ tag = "#{seg.toLowerCase()}.#{i+1}"
247
+ tag += "(#{j+1})" if all.length > 1
248
+ console.log "#{tag}#{pad[tag.length..-1]}#{rep}"
249
+
250
+ # ==[ Helpers ]==
251
+
252
+ name: (person) -> [
253
+ person.last_name
254
+ person.first_name
255
+ person.middle_name or ''
256
+ ].join('^')
257
+
258
+ address: (address) -> [
259
+ get(address.street, 30)
260
+ get(address.city, 25) # sometimes only 15?
261
+ get(address.state)
262
+ get(address.zip).replace('-', '')
263
+ ].join('|')
264
+
265
+ module.exports = Bar
266
+
267
+ # ==[ Command line invocation ]==
268
+
269
+ if !module.parent
270
+ fs = require 'fs'
271
+
272
+ list = process.argv.slice 2
273
+
274
+ for file in list
275
+ console.log "\n==[ #{file} ]==\n"
276
+ try
277
+ bar = new Bar fs.readFileSync(file).toString()
278
+ bar.show()
279
+ catch
280
+ console.log "Invalid\n"
281
+
282
+ ###
283
+
284
+ # ==[ Testing ]==
285
+
286
+ p = -> console.log arg for arg in arguments
287
+ exit = require('process').exit
288
+
289
+ PDF417 = require './pdf-417'
290
+
291
+ do ->
292
+ # x = ". Operators with higher precedence are evaluated first.\n\nA common example:\n\n3 + 4 * 5 // returns 23\nThe multiplication operator (\"*\") has higher precedence than the addition operator (\"+\") and thus will be evaluated first.\n\nAssociativity\nAssociativity determines the order in which operators of the same precedence are processed. For example, consider an expression:\n\na OP b OP c\nLeft-associativity (left-to-right) means that it is processed as (a OP b) OP c, while right-associativity (right-to-left) means it is interpreted as a OP (b OP c). Assignment operators are right-associative, so you can write:\n\na = b = 5;\nwith the expected result that a and b get the value 5. This is because the assignment operator returns the value that it assigned. First, b is set to 5. Then the a is also set to 5, the return value of b = 5, aka right operand of the assignment."
293
+ # y = new PDF417(x).generate()
294
+
295
+ x = ". Operator"
296
+ y = new PDF417(x)
297
+ z = await y.to_png()
298
+ p z.toString()
299
+
300
+ p new Bar """
301
+ H|XHR1.0|#{time(8)}|E
302
+ P|XYZ999||||||123456|999888777|TEST^SON^|19850615|M|||||||03||TEST^DAD^||123 Main|Anytown|CA|93456||3||DOCTOR^BOB^|||334455||||^|||||||||^|||||||N||^^^^^^^^^^^^^^|^^^^^^^||||||||||||||||1407891260|||||
303
+ C||||||||||||||||N|#{time(8)}||^|||LCM|QA09|N|0847||
304
+ T|500918||||||||||||||||||||||||||||||||||||||||
305
+ S|500918^A^TNG^ANT^^^This is the tongue.~500918^B^TNGBS^^^^This is the base of the tongue.~500918^C^TNGBR^^^^This is the border of the tongue.~500918^D^TNGS^D^^^This is the surface of the tongue.|
306
+ D|F16.183^I63.10^S33.131D||
307
+ L|680|
308
+ E|0|
309
+ """
310
+
311
+ # p new Bar """
312
+ # h.1 XHR1.0
313
+ # h.2 #{time(8)}
314
+ # h.3 E
315
+ # p.1 XYZ999
316
+ # p.7 123456
317
+ # p.8 999888777
318
+ # p.9-1 TEST
319
+ # p.9-2 SON
320
+ # p.10 19850615
321
+ # p.11 M
322
+ # p.18 03
323
+ # p.20-1 TEST
324
+ # p.20-2 DAD
325
+ # p.22 123 Main
326
+ # p.23 Anytown
327
+ # p.24 CA
328
+ # p.25 93456
329
+ # p.27 3
330
+ # p.29-1 DOCTOR
331
+ # p.29-2 BOB
332
+ # p.32 334455
333
+ # p.52 N
334
+ # p.71 1407891260
335
+ # c.16 N
336
+ # c.17 #{time(8)}
337
+ # c.22 LCM
338
+ # c.23 QA09
339
+ # c.24 N
340
+ # c.25 0847
341
+ # t.1 500918
342
+ # s.1-1 500918
343
+ # s.1-2 A
344
+ # s.1-3 TNG
345
+ # s.1-4 ANT
346
+ # s.1-7 This is the tongue.
347
+ # s.1(2)-1 500918
348
+ # s.1(2)-2 B
349
+ # s.1(2)-3 TNGBS
350
+ # s.1(2)-7 This is the base of the tongue.
351
+ # s.1(3)-1 500918
352
+ # s.1(3)-2 C
353
+ # s.1(3)-3 TNGBR
354
+ # s.1(3)-7 This is the border of the tongue.
355
+ # s.1(4)-1 500918
356
+ # s.1(4)-2 D
357
+ # s.1(4)-3 TNGS
358
+ # s.1(4)-4 D
359
+ # s.1(4)-7 This is the surface of the tongue.
360
+ # d.1-1 F16.183
361
+ # d.1-2 I63.10
362
+ # d.1-3 S33.131D
363
+ # l.1 680
364
+ # e.1 0
365
+ # """
366
+
367
+ # PDF417.to_png("real.png", x.to_s("\r"))
368
+
369
+ # return png image
370
+ to_png(bar)
371
+
372
+ # "H|LCM04.06.10|20130628||^^|PA|\r"
373
+ # "P||1033|Y|N|||05330010|200975012250|TESTY^TESTER^|19800101|M|123456789|100 FAST LANE|Huntsville|AL|35806|2567211139|XI||TESTY^TESTER^|123456789|100 FAST LANE|Huntsville|AL|35806||1||PETERSON^ALAN^|1234567890||B47114||CIGNH||^||||ABCD1231234|||AARPA||^||||123456789|||N||^^^^^^^^^^^^^^|^^^^^^^|2567211139||||||||||*||190||67|1477555225|^^|^^|^^|^^|||C|17930500030^2013|1||Y||N|\r"
374
+ # "C||||||||||||||||N|20130628|500|^|||LCM|HVQ5|N|1252||"
375
+ # "A|||190|1|C|N||||X|X||20121111||||X||||22.2^20121111^22.2|22.2^22.2|Y^3|N||N|Y|N|Y^^|^^^^^|||"
376
+ # "T|X02123|010801|276024|998085|||||||||||||||||||||||||||||||||||||"
377
+ # "M||||||"
378
+ # "B|||||||||||||||||||||"
379
+ # "K|^|||||||||||||||^^^^||||||"
380
+ # "I|1^1^005|2^1^001|^^|^^|^^|^^|^^|^^|"
381
+ # "L|752|"
382
+ # "E|6|"
383
+
384
+ # "Quest: ||||||^GEBERT-PARIKH^CHRIS^^^^^^UPIN~1366608093^GEBERT-PARIKH^CHRIS^^^^^^NPI|||||||||||^^^^^^|"
385
+ # "OBR|3|0023686||^^^1759^CBC (H/H, RBC, INDICES, WBC, PLT)^MET|||20170320153400|||||||||^GEBERT-PARIKH^CHRIS^^^^^^UPIN~1366608093^GEBERT-PARIKH^CHRIS^^^^^^NPI|||||||||||^^^^^^|"
386
+ # "OBR|4|0023686||^^^10231^COMPREHENSIVE METABOLIC PANEL^MET|||20170320153400|||||||||^GEBERT-PARIKH^CHRIS^^^^^^UPIN~1366608093^GEBERT-PARIKH^CHRIS^^^^^^NPI|||||||||||^^^^^^|"
387
+ # "928289728728728272"
388
+ # "OBR|5|0023686||^^^17306^VITAMIN D, 25-HYDROXY, TOTAL, IMMUNOASSAY^MET|||20170320153400|||||||||^GEBERT-PARIKH^CHRIS^^^^^^UPIN~1366608093^GEBERT-PARIKH^CHRIS^^^^^^NPI|||||||||||^^^^^^|"
389
+ # "DG1|1|ICD|Z0000||"
390
+ # "DG1|2|ICD|Z8679||"
391
+ # "DG1|3|ICD|Z862||"
392
+ # "FTS|1041667412||
393
+
394
+ ###
package/bin/rip ADDED
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
4
+ import { execSync } from 'child_process';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname, join } from 'path';
7
+ import { Compiler } from '../src/compiler.js';
8
+ import { startREPL } from '../src/repl.js';
9
+ import packageJson from '../package.json' with { type: 'json' };
10
+
11
+ // Get the directory where this script lives
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+
15
+ const VERSION = packageJson.version;
16
+ const SUMMARY = packageJson.description;
17
+
18
+ function printHelp() {
19
+ console.log(`
20
+ Rip ${VERSION} - ${SUMMARY}
21
+
22
+ Usage:
23
+ rip [options] [file]
24
+ rip # Start interactive REPL (no arguments)
25
+
26
+ Options:
27
+ -c, --compile Show compiled JavaScript (compile mode)
28
+ -h, --help Show this help message
29
+ -o, --output <file> Write JavaScript to file
30
+ -q, --quiet Suppress headers (with -c)
31
+ -r, --repl Start interactive REPL
32
+ -s, --sexpr Show s-expressions
33
+ -t, --tokens Show token stream
34
+ -v, --version Show version number
35
+
36
+ Examples:
37
+ rip # Interactive REPL
38
+ rip script.rip # Execute script (auto-detects .rip)
39
+ rip script.rip arg1 arg2 # Execute with arguments
40
+ rip -c example.rip # Compile to stdout
41
+ rip -q example.rip # Just the JS (for piping)
42
+ rip -o output.js example.rip # Save to file
43
+ rip -s -t example.rip # Show everything (debug mode)
44
+ echo 'x = 1 + 2' | rip # Read from stdin
45
+
46
+ Shebang support:
47
+ #!/usr/bin/env rip # Execute with rip
48
+ #!/usr/bin/env bun # Execute with bun (also works)
49
+ `);
50
+ }
51
+
52
+ async function main() {
53
+ const args = process.argv.slice(2);
54
+
55
+ if (args.includes('-h') || args.includes('--help')) {
56
+ printHelp();
57
+ process.exit(0);
58
+ }
59
+
60
+ if (args.includes('-v') || args.includes('--version')) {
61
+ console.log(`Rip ${VERSION} - ${SUMMARY}`);
62
+ process.exit(0);
63
+ }
64
+
65
+ // Check if REPL should be started
66
+ // Launch REPL if: no args AND stdin is a TTY (not piped), OR explicit -r flag
67
+ const isTTY = process.stdin.isTTY;
68
+ if ((args.length === 0 && isTTY) || args.includes('-r') || args.includes('--repl')) {
69
+ startREPL();
70
+ return;
71
+ }
72
+
73
+ const options = {
74
+ compile: args.includes('-c') || args.includes('--compile'),
75
+ showTokens: args.includes('-t') || args.includes('--tokens'),
76
+ showSExpr: args.includes('-s') || args.includes('--sexpr'),
77
+ quiet: args.includes('-q') || args.includes('--quiet')
78
+ };
79
+
80
+ // Find input file (last non-option argument)
81
+ let inputFile = null;
82
+ let outputFile = null;
83
+
84
+ for (let i = 0; i < args.length; i++) {
85
+ if (args[i] === '-o' || args[i] === '--output') {
86
+ outputFile = args[i + 1];
87
+ i++;
88
+ } else if (!args[i].startsWith('-') && !inputFile) {
89
+ inputFile = args[i]; // Only take first non-option as input file
90
+ }
91
+ }
92
+
93
+ // If .rip file without compile flags → execute instead of compile
94
+ const hasCompileFlag = options.compile || options.showTokens || options.showSExpr || outputFile;
95
+ if (inputFile && inputFile.endsWith('.rip') && !hasCompileFlag) {
96
+ // Check if file exists
97
+ if (!existsSync(inputFile)) {
98
+ console.error(`Error: File not found: ${inputFile}`);
99
+ process.exit(1);
100
+ }
101
+
102
+ // Execute the script with Bun using our loader
103
+ const loaderPath = join(__dirname, '../rip-loader.ts');
104
+
105
+ // Get script arguments (everything after the input file)
106
+ const inputFileIndex = args.indexOf(inputFile);
107
+ const scriptArgs = args.slice(inputFileIndex + 1);
108
+
109
+ try {
110
+ execSync(`bun --preload ${loaderPath} ${inputFile} ${scriptArgs.join(' ')}`, {
111
+ stdio: 'inherit'
112
+ });
113
+ process.exit(0);
114
+ } catch (error) {
115
+ process.exit(error.status || 1);
116
+ }
117
+ }
118
+
119
+ let source;
120
+
121
+ try {
122
+ if (!inputFile) {
123
+ // Read from stdin if no file specified (file descriptor 0)
124
+ source = readFileSync(0, 'utf-8');
125
+ } else {
126
+ // Check if file exists first
127
+ if (!existsSync(inputFile)) {
128
+ console.error(`Error: File not found: ${inputFile}`);
129
+ process.exit(1);
130
+ }
131
+ // Read source file
132
+ source = readFileSync(inputFile, 'utf-8');
133
+ }
134
+
135
+ // Compile
136
+ const compiler = new Compiler(options);
137
+ const result = compiler.compile(source);
138
+
139
+ // Output
140
+ if (outputFile) {
141
+ // Save to file
142
+ writeFileSync(outputFile, result.code, 'utf-8');
143
+ if (!options.quiet) {
144
+ console.log(`Compiled to ${outputFile}`);
145
+ }
146
+ } else {
147
+ // Default mode - compile and output to stdout
148
+ if (!options.quiet) {
149
+ console.log(`// == JavaScript output by Rip ${VERSION} == //\n`);
150
+ }
151
+ console.log(result.code);
152
+ }
153
+ } catch (error) {
154
+ console.error('Compilation Error:', error.message);
155
+ if (error.stack) {
156
+ console.error(error.stack);
157
+ }
158
+ process.exit(1);
159
+ }
160
+ }
161
+
162
+ main();