atomy 0.1.1 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.md +201 -0
  4. data/bin/atomy +16 -133
  5. data/kernel/array.ay +6 -0
  6. data/kernel/atomy.ay +18 -0
  7. data/kernel/condition.ay +171 -271
  8. data/kernel/control-flow.ay +197 -192
  9. data/kernel/core.ay +120 -0
  10. data/kernel/data.ay +83 -39
  11. data/kernel/define.ay +84 -93
  12. data/kernel/doc.ay +282 -449
  13. data/kernel/dynamic.ay +25 -29
  14. data/kernel/file.ay +9 -0
  15. data/kernel/grammar.ay +267 -0
  16. data/kernel/hash.ay +17 -0
  17. data/kernel/interpolation.ay +59 -0
  18. data/kernel/io.ay +70 -244
  19. data/kernel/let-macro.ay +24 -0
  20. data/kernel/let-pattern.ay +24 -0
  21. data/kernel/loop.ay +80 -0
  22. data/kernel/mutation.ay +53 -0
  23. data/kernel/particles.ay +176 -39
  24. data/kernel/patterns.ay +527 -191
  25. data/kernel/pretty.ay +311 -277
  26. data/kernel/quotes.ay +29 -0
  27. data/kernel/range.ay +4 -0
  28. data/kernel/regexp.ay +23 -0
  29. data/kernel/repl.ay +83 -109
  30. data/kernel/stack-local.ay +21 -0
  31. data/lib/atomy.rb +37 -0
  32. data/lib/atomy/bootstrap.rb +256 -0
  33. data/lib/atomy/code/assign.rb +64 -0
  34. data/lib/atomy/code/block.rb +98 -0
  35. data/lib/atomy/code/class_variable.rb +17 -0
  36. data/lib/atomy/code/constant.rb +21 -0
  37. data/lib/atomy/code/define.rb +242 -0
  38. data/lib/atomy/code/define_function.rb +51 -0
  39. data/lib/atomy/code/define_method.rb +20 -0
  40. data/lib/atomy/code/false.rb +9 -0
  41. data/lib/atomy/code/instance_variable.rb +15 -0
  42. data/lib/atomy/code/integer.rb +13 -0
  43. data/lib/atomy/code/list.rb +17 -0
  44. data/lib/atomy/code/nil.rb +9 -0
  45. data/lib/atomy/code/pattern.rb +23 -0
  46. data/lib/atomy/code/pattern/and.rb +61 -0
  47. data/lib/atomy/code/pattern/quasi_quote.rb +185 -0
  48. data/lib/atomy/code/pattern/splat.rb +29 -0
  49. data/lib/atomy/code/pattern/wildcard.rb +37 -0
  50. data/lib/atomy/code/quasi_quote.rb +118 -0
  51. data/lib/atomy/code/quote.rb +13 -0
  52. data/lib/atomy/code/self.rb +9 -0
  53. data/lib/atomy/code/send.rb +110 -0
  54. data/lib/atomy/code/sequence.rb +23 -0
  55. data/lib/atomy/code/string_literal.rb +53 -0
  56. data/lib/atomy/code/symbol.rb +13 -0
  57. data/lib/atomy/code/true.rb +9 -0
  58. data/lib/atomy/code/undefined.rb +9 -0
  59. data/lib/atomy/code/variable.rb +17 -0
  60. data/lib/atomy/codeloader.rb +218 -0
  61. data/lib/atomy/compiler.rb +57 -0
  62. data/lib/atomy/errors.rb +54 -0
  63. data/lib/atomy/grammar.rb +2278 -0
  64. data/lib/atomy/locals.rb +75 -0
  65. data/lib/atomy/message_structure.rb +277 -0
  66. data/lib/atomy/method.rb +343 -0
  67. data/lib/atomy/module.rb +144 -0
  68. data/lib/atomy/node/constructable.rb +169 -0
  69. data/lib/atomy/node/equality.rb +113 -0
  70. data/lib/atomy/node/meta.rb +206 -0
  71. data/lib/atomy/node/pretty.rb +108 -0
  72. data/lib/atomy/parser.rb +21 -0
  73. data/lib/atomy/pattern.rb +26 -0
  74. data/lib/atomy/pattern/and.rb +59 -0
  75. data/lib/atomy/pattern/attribute.rb +16 -0
  76. data/lib/atomy/pattern/class_variable.rb +15 -0
  77. data/lib/atomy/pattern/equality.rb +42 -0
  78. data/lib/atomy/pattern/instance_variable.rb +15 -0
  79. data/lib/atomy/pattern/kind_of.rb +20 -0
  80. data/lib/atomy/pattern/or.rb +48 -0
  81. data/lib/atomy/pattern/quasi_quote.rb +164 -0
  82. data/lib/atomy/pattern/splat.rb +15 -0
  83. data/lib/atomy/pattern/wildcard.rb +18 -0
  84. data/lib/atomy/rubygems.rb +48 -0
  85. data/lib/atomy/version.rb +3 -0
  86. metadata +169 -134
  87. data/COPYING +0 -30
  88. data/README.md +0 -1
  89. data/kernel/block.ay +0 -30
  90. data/kernel/boot.ay +0 -10
  91. data/kernel/comparison.ay +0 -61
  92. data/kernel/concurrency.ay +0 -84
  93. data/kernel/cosmetics.ay +0 -3
  94. data/kernel/data-delta.ay +0 -105
  95. data/kernel/documentation.ay +0 -135
  96. data/kernel/errors.ay +0 -6
  97. data/kernel/format.ay +0 -13
  98. data/kernel/format/data.ay +0 -89
  99. data/kernel/format/formatter.ay +0 -345
  100. data/kernel/format/parser.ay +0 -13
  101. data/kernel/hashes.ay +0 -39
  102. data/kernel/namespaces.ay +0 -63
  103. data/kernel/node.ay +0 -48
  104. data/kernel/operators.ay +0 -28
  105. data/kernel/precision.ay +0 -148
  106. data/kernel/therie.ay +0 -204
  107. data/lib/ast/binary_send.rb +0 -44
  108. data/lib/ast/block.rb +0 -268
  109. data/lib/ast/constant.rb +0 -88
  110. data/lib/ast/internal/assign.rb +0 -19
  111. data/lib/ast/internal/block_pass.rb +0 -21
  112. data/lib/ast/internal/catch.rb +0 -247
  113. data/lib/ast/internal/class.rb +0 -30
  114. data/lib/ast/internal/class_variable.rb +0 -23
  115. data/lib/ast/internal/define.rb +0 -174
  116. data/lib/ast/internal/ensure.rb +0 -135
  117. data/lib/ast/internal/file.rb +0 -14
  118. data/lib/ast/internal/global_variable.rb +0 -20
  119. data/lib/ast/internal/if_then_else.rb +0 -24
  120. data/lib/ast/internal/instance_variable.rb +0 -17
  121. data/lib/ast/internal/let_macro.rb +0 -35
  122. data/lib/ast/internal/macro_quote.rb +0 -23
  123. data/lib/ast/internal/match.rb +0 -53
  124. data/lib/ast/internal/module.rb +0 -30
  125. data/lib/ast/internal/pattern.rb +0 -17
  126. data/lib/ast/internal/return.rb +0 -29
  127. data/lib/ast/internal/set.rb +0 -19
  128. data/lib/ast/internal/singleton_class.rb +0 -18
  129. data/lib/ast/internal/splat.rb +0 -14
  130. data/lib/ast/internal/when.rb +0 -24
  131. data/lib/ast/list.rb +0 -25
  132. data/lib/ast/macro.rb +0 -37
  133. data/lib/ast/node.rb +0 -599
  134. data/lib/ast/operator.rb +0 -21
  135. data/lib/ast/particle.rb +0 -13
  136. data/lib/ast/primitive.rb +0 -20
  137. data/lib/ast/quasi_quote.rb +0 -20
  138. data/lib/ast/quote.rb +0 -13
  139. data/lib/ast/send.rb +0 -104
  140. data/lib/ast/splice.rb +0 -32
  141. data/lib/ast/string.rb +0 -23
  142. data/lib/ast/unary.rb +0 -44
  143. data/lib/ast/unquote.rb +0 -45
  144. data/lib/ast/variable.rb +0 -64
  145. data/lib/atomy.kpeg.rb +0 -3995
  146. data/lib/code_loader.rb +0 -137
  147. data/lib/compiler/compiler.rb +0 -155
  148. data/lib/compiler/stages.rb +0 -81
  149. data/lib/formatter.kpeg.rb +0 -1394
  150. data/lib/macros.rb +0 -317
  151. data/lib/method.rb +0 -261
  152. data/lib/namespace.rb +0 -236
  153. data/lib/parser.rb +0 -28
  154. data/lib/patterns.rb +0 -276
  155. data/lib/patterns/any.rb +0 -21
  156. data/lib/patterns/attribute.rb +0 -59
  157. data/lib/patterns/block_pass.rb +0 -54
  158. data/lib/patterns/constant.rb +0 -33
  159. data/lib/patterns/default.rb +0 -44
  160. data/lib/patterns/head_tail.rb +0 -63
  161. data/lib/patterns/list.rb +0 -77
  162. data/lib/patterns/match.rb +0 -45
  163. data/lib/patterns/named.rb +0 -55
  164. data/lib/patterns/named_class.rb +0 -46
  165. data/lib/patterns/named_global.rb +0 -46
  166. data/lib/patterns/named_instance.rb +0 -46
  167. data/lib/patterns/particle.rb +0 -29
  168. data/lib/patterns/quasi_quote.rb +0 -184
  169. data/lib/patterns/quote.rb +0 -33
  170. data/lib/patterns/singleton_class.rb +0 -31
  171. data/lib/patterns/splat.rb +0 -57
  172. data/lib/util.rb +0 -37
data/kernel/dynamic.ay CHANGED
@@ -1,42 +1,38 @@
1
- Atomy::DYNAMIC_ROOTS = Hash new
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+ use(require("data"))
5
+ use(require("hash"))
2
6
 
3
- for-macro:
4
- key(n) :=
5
- Atomy::AST::Variable new $:
6
- n line
7
- "atomy_" + n resolve message-name
7
+ stack-local = require("stack-local")
8
8
 
9
- dynvar(x) :=
10
- `(Thread current [#~key(x)] || Atomy::DYNAMIC_ROOTS [#~x])
9
+ data(Dynvar(@default))
11
10
 
12
- set-dynvar(n, v) :=
13
- `(Thread current [#~key(n)] = ~v)
11
+ def(^Dynvar): values fetch(Thread current): @default
12
+ def(Dynvar get): values fetch(Thread current): _
13
+ def(Dynvar set(x)):
14
+ if(x == _)
15
+ then: values delete(Thread current)
16
+ else: values[Thread current] = x
14
17
 
15
- macro(dynamic(n, root)):
16
- where = Atomy::Namespace define-target
18
+ -- TODO: this should be private
19
+ def(Dynvar values): @values = (@values || #{})
17
20
 
18
- Atomy::Namespace register(n namespace-symbol, where)
21
+ macro(dynamic): `dynamic(_)
22
+ macro(dynamic(~default)): `(Dynvar new(~default))
19
23
 
20
- Atomy::CodeLoader when-load <<
21
- [`(Atomy::Namespace register(~(n namespace-symbol), ~where)), true]
24
+ macro(with(~*bindings): ~*body):
25
+ tmps = bindings collect [b]: [b, stack-local Local new]
22
26
 
23
- `(Atomy::DYNAMIC_ROOTS [#~n] = ~root)
27
+ save = tmps collect [`(~n = ~_), tmp]: tmp set(`(~n get))
24
28
 
25
- macro(^x): dynvar(x)
29
+ set = bindings collect [`(~n = ~v)]: `(~n set(~v))
26
30
 
27
- macro(let(*bindings, &body)):
28
- tmps = names(bindings size)
29
- save = []
30
- set = []
31
- restore = []
32
-
33
- bindings zip(tmps) [[`(~n = ~v), tmp]]:
34
- save << `(~tmp = ~(dynvar(n)))
35
- set << set-dynvar(n, v)
36
- restore << set-dynvar(n, tmp)
31
+ restore = tmps collect [`(~n = ~_), tmp]: `(~n set(~tmp))
37
32
 
38
33
  `(do:
39
34
  ~*save
40
- { ~*set
41
- ~(body caller)
35
+ do {
36
+ ~*set
37
+ ~*body
42
38
  } ensuring: ~*restore)
data/kernel/file.ay ADDED
@@ -0,0 +1,9 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+
4
+ file = class:
5
+ def(bytecode(gen, mod)):
6
+ gen push-scope
7
+ gen send(.active-path, 0)
8
+
9
+ macro(__FILE__): file new
data/kernel/grammar.ay ADDED
@@ -0,0 +1,267 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+ use(require("dynamic"))
5
+ use(require("particles"))
6
+
7
+ stack-local = require("stack-local")
8
+
9
+ require("kpeg")
10
+ require("kpeg/compiled_parser")
11
+ require("rubinius/processor") -- needed by compiler
12
+ require("rubinius/melbourne") -- needed by compiler
13
+ require("rubinius/compiler")
14
+ require("set")
15
+
16
+
17
+ -- lazily load these modules to prevent circular dependency
18
+ loaded-pretty = nil
19
+ fn(pretty): &loaded-pretty = (loaded-pretty || require("pretty"))
20
+
21
+ loaded-interpolation = nil
22
+ fn(intp): &loaded-interpolation = (loaded-interpolation || require("interpolation"))
23
+
24
+
25
+ actions = dynamic
26
+ setups = dynamic
27
+ vars = dynamic
28
+ rule = dynamic
29
+ rule-vars = dynamic
30
+
31
+ fn(const-name(c & Atomy Grammar AST Compose)): [const-name(c left), "::", const-name(c right)] join
32
+ fn(const-name(c & Atomy Grammar AST Constant)): c text to-s
33
+
34
+ fn(process-val(g, `(%(~grammar)(~name)(~*args)))):
35
+ `(~g foreign-invoke(
36
+ .~grammar
37
+ .~name
38
+ ~(args collect &.(pretty show(_)) join(", "))))
39
+
40
+ fn(process-val(g, `(%(~grammar)(~name)))):
41
+ `(~g foreign-invoke(.~grammar, .~name))
42
+
43
+ fn(process-val(g, `((~name)=(~v)))):
44
+ val = process-val(g, v)
45
+
46
+ when(^rule-vars):
47
+ ^rule-vars << name text
48
+
49
+ `(~g t(~val, ~(Atomy Grammar AST StringLiteral new(name text to-s))))
50
+
51
+ fn(process-val(g, `(~a ~b))):
52
+ `(~g seq(~process-val(g, a), ~process-val(g, b)))
53
+
54
+ fn(process-val(g, `(~a | ~b))):
55
+ process-val(g, `[~a, ~b])
56
+
57
+ fn(process-val(g, `[~*xs])):
58
+ original = ^rule-vars
59
+ new = Set new
60
+ choices =
61
+ xs collect [x]:
62
+ with(rule-vars = original dup):
63
+ choice = process-val(g, x)
64
+ new merge(^rule-vars - original)
65
+ choice
66
+
67
+ ^rule-vars merge(new)
68
+
69
+ `(~g any(~*choices))
70
+
71
+ fn(process-val(g, a & `{ ~*bs })):
72
+ if(^actions)
73
+ then:
74
+ vars = ^rule-vars to-a
75
+
76
+ call = [
77
+ "actions["
78
+ ^actions size to-s
79
+ "]["
80
+ vars collect &.to-s join(", ")
81
+ "]"
82
+ ] join
83
+
84
+ ^actions << [a, vars]
85
+ `(~g action(~(Atomy Grammar AST StringLiteral new(call))))
86
+ else:
87
+ `(~g action({ ~*bs }))
88
+
89
+ fn(process-val(g, `(<(~x)>))):
90
+ val = process-val(g, x)
91
+
92
+ when(^rule-vars):
93
+ ^rule-vars << .text
94
+
95
+ `(~g collect(~val))
96
+
97
+ fn(process-val(g, `(@<(~x)>))):
98
+ `(~g bounds(~process-val(g, x)))
99
+
100
+ fn(process-val(g, `((~v)?))):
101
+ `(~g maybe(~process-val(g, v)))
102
+
103
+ fn(process-val(g, `((~v)+))):
104
+ `(~g many(~process-val(g, v)))
105
+
106
+ fn(process-val(g, `((~v)*))):
107
+ `(~g kleene(~process-val(g, v)))
108
+
109
+ fn(process-val(g, `&~v)):
110
+ `(~g andp(~process-val(g, v)))
111
+
112
+ fn(process-val(g, `!~v)):
113
+ `(~g notp(~process-val(g, v)))
114
+
115
+ fn(process-val(g, '_)):
116
+ `(~g dot)
117
+
118
+ fn(process-val(g, `(/(~(b & Atomy Grammar AST StringLiteral))/))):
119
+ if(^actions)
120
+ then:
121
+ vars = ^rule-vars to-a
122
+
123
+ -- this is a bit gross because it has to parse as a valid regexp
124
+ -- so we use .call() because actions[0][] is invalid
125
+ --
126
+ -- should be fine as the embedded parts are limited to numbers and words
127
+ call = [
128
+ "#{actions["
129
+ ^actions size to-s
130
+ "].call("
131
+ vars collect &.to-s join(", ")
132
+ ")}"
133
+ ] join
134
+
135
+ ^actions << [`{ ~(intp interpolated(b value)) }, vars]
136
+
137
+ `(~g reg(~(Atomy Grammar AST StringLiteral new(call))))
138
+ else:
139
+ `(~g reg(r~b))
140
+
141
+ fn(process-val(g, s & Atomy Grammar AST StringLiteral)):
142
+ `(~g str(~s))
143
+
144
+ fn(process-val(g, w & Atomy Grammar AST Word)):
145
+ `(~g ref(~(Atomy Grammar AST StringLiteral new(w text to-s))))
146
+
147
+ fn(process-val(g, `@~(w & Atomy Grammar AST Word))):
148
+ `(~g invoke(~(Atomy Grammar AST StringLiteral new(w text to-s))))
149
+
150
+ fn(process-val(g, `^~(w & Atomy Grammar AST Word))):
151
+ `(~g foreign-invoke("parent", ~(Atomy Grammar AST StringLiteral new(w text to-s))))
152
+
153
+ fn(process-val(g, c & Atomy Grammar AST Apply)):
154
+ args = [
155
+ "("
156
+ c arguments collect &.(pretty show(_)) join(", ")
157
+ ")"
158
+ ] join
159
+
160
+ `(~g ref(~(Atomy Grammar AST StringLiteral new(c node text to-s)), nil, ~(Atomy Grammar AST StringLiteral new(args))))
161
+
162
+ fn(process-val(g, `@~(c & Atomy Grammar AST Apply))):
163
+ args = [
164
+ "("
165
+ c arguments collect &.(pretty show(_)) join(", ")
166
+ ")"
167
+ ] join
168
+
169
+ `(~g invoke(~(Atomy Grammar AST StringLiteral new(c node text to-s)), ~(Atomy Grammar AST StringLiteral new(args))))
170
+
171
+ fn(process-val(g, `^~(c & Atomy Grammar AST Apply))):
172
+ args = [
173
+ "("
174
+ c arguments collect &.(pretty show(_)) join(", ")
175
+ ")"
176
+ ] join
177
+
178
+ `(~g foreign-invoke("parent", ~(Atomy Grammar AST StringLiteral new(c node text to-s)), ~(Atomy Grammar AST StringLiteral new(args))))
179
+
180
+ fn(process-val(_, s)):
181
+ raise(ArgumentError, "unknown parsing operator:\n" + s inspect)
182
+
183
+ parser-definer = class:
184
+ def(initialize(@source)) {}
185
+
186
+ def(bytecode(gen, mod)):
187
+ gen push-rubinius
188
+ gen push-literal(.__parser_init__)
189
+ gen push-literal(CodeTools Compiler compile-string(@source))
190
+ gen push-scope
191
+ gen push-self
192
+ gen send(.attach-method, 4)
193
+ gen pop
194
+
195
+ gen push-self
196
+ gen send(.__parser_init__, 0)
197
+
198
+
199
+ fn(process-toplevel(grammar, `%%{ ~*xs })):
200
+ call =
201
+ if(^setups)
202
+ then:
203
+ ^setups << `{ ~*xs }
204
+ Atomy Grammar AST StringLiteral new(["setups[", (^setups size - 1) to-s, "][]"] join)
205
+ else:
206
+ `{ ~*xs }
207
+
208
+ `(~grammar add-setup(~grammar action(~call)))
209
+
210
+ fn(process-toplevel(grammar, `(%~name = ~const))):
211
+ `(~grammar add-foreign-grammar(
212
+ ~(Atomy Grammar AST StringLiteral new(name text to-s))
213
+ ~(Atomy Grammar AST StringLiteral new(const-name(const)))
214
+ ))
215
+
216
+ fn(process-toplevel(grammar, `(rule((~name)(~*args)): ~val))):
217
+ with(rule = name text, rule-vars = //Set new(args collect &.text)):
218
+ `(~grammar set(
219
+ ~(Atomy Grammar AST StringLiteral new(name text to-s))
220
+ ~process-val(grammar, val)
221
+ [~*(args collect [x]: Atomy Grammar AST StringLiteral new(x text to-s))]
222
+ ))
223
+
224
+ fn(process-toplevel(grammar, `(rule(~name): ~val))):
225
+ with(rule = name text, rule-vars = //Set new):
226
+ `(~grammar set(
227
+ ~(Atomy Grammar AST StringLiteral new(name text to-s))
228
+ ~process-val(grammar, val)
229
+ ))
230
+
231
+ fn(process-toplevel(grammar, u)):
232
+ raise("unknown toplevel grammar form:\n" + u inspect)
233
+
234
+ macro(grammar: ~*body):
235
+ grammar = stack-local Local new
236
+
237
+ `(do:
238
+ ~(grammar set(`(//KPeg Grammar new)))
239
+ ~*(body collect [n]: process-toplevel(grammar, n))
240
+ ~grammar)
241
+
242
+
243
+ macro(parser(~name): ~*grammar):
244
+ with(actions = [], setups = [], vars = []):
245
+ g = evaluate(`(grammar: ~*grammar))
246
+
247
+ acts =
248
+ ^actions collect [action, as]:
249
+ args = as collect [a]: Word new(a)
250
+ `([~*args] ~action)
251
+
252
+ def = parser-definer new(//KPeg CodeGenerator new(const-name(name), g) output)
253
+
254
+ `(do:
255
+ //KPeg CompiledParser class(~name):
256
+ setups = [~*^setups]
257
+ vars = [~*^vars]
258
+
259
+ singleton:
260
+ def(setups): setups
261
+ def(vars): vars
262
+
263
+ def(actions): @actions ||= [~*acts]
264
+
265
+ ~def
266
+
267
+ ~name)
data/kernel/hash.ay ADDED
@@ -0,0 +1,17 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+ use(require("patterns"))
5
+
6
+ stack-local = require("stack-local")
7
+
8
+ -- hash literals
9
+ macro(#{ ~*pairs }):
10
+ hash = stack-local Local new
11
+
12
+ init-hash = `(//Hash new-from-literal(~(Number new(pairs size))))
13
+
14
+ `(do:
15
+ ~(hash set(init-hash))
16
+ ~*(pairs collect [`(~k -> ~v)]: `(~hash [~k] = ~v))
17
+ ~hash)
@@ -0,0 +1,59 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+ use(require("quotes"))
5
+ use(require("range"))
6
+ use(require("grammar"))
7
+ use(require("patterns"))
8
+
9
+ parser(Parser):
10
+ %atomy = Atomy Grammar
11
+
12
+ rule(root): %atomy(wsp) es=(%atomy(expressions)) %atomy(wsp) "}" {
13
+ Atomy Grammar AST Sequence new(Array(es))
14
+ }
15
+
16
+ fn(intp-segments(s)):
17
+ s split(Regexp new("(?<!\\\\)#\\{"), 2) match:
18
+ []: ['""]
19
+
20
+ [x]: [Atomy Code StringLiteral new(x, true)]
21
+
22
+ [pre, chunk]:
23
+ p = Parser new(chunk)
24
+
25
+ unless(p parse):
26
+ p raise-error
27
+
28
+ segments = [Atomy Code StringLiteral new(pre, true), `(~(p result) to-s)]
29
+
30
+ rest = p string[p pos .. -1]
31
+
32
+ if(rest nil? || rest empty?)
33
+ then: segments
34
+ else: segments + intp-segments(rest)
35
+
36
+
37
+ interpolation = class:
38
+ def(initialize(@segments)) {}
39
+
40
+ def(interpolated?): @segments size > 1
41
+
42
+ def(bytecode(gen, mod)):
43
+ @segments each [s]:
44
+ mod compile(gen, s)
45
+
46
+ when(interpolated?):
47
+ gen string-build(@segments size)
48
+
49
+
50
+ def(interpolated(x)): interpolation new(intp-segments(x))
51
+
52
+ macro-quoter(i) [_, _, v]: interpolated(v)
53
+
54
+ -- symbol literals with interpolation
55
+ macro(.~(x & StringLiteral)):
56
+ i = interpolated(x value)
57
+ if(i interpolated?)
58
+ then: `(~i to-sym)
59
+ else: Atomy Code Symbol new(x value to-sym)
data/kernel/io.ay CHANGED
@@ -1,244 +1,70 @@
1
- namespace(atomy)
2
-
3
- -- condition kernel not loaded yet; predeclare this
4
- symbols(error)
5
-
6
- title"Input & Output"
7
-
8
- doc"Where to write normal output." for:
9
- dynamic(output-port, $stdout)
10
-
11
- doc"Where to read input from." for:
12
- dynamic(input-port, $stdin)
13
-
14
- doc"Where to write error/warning output." for:
15
- dynamic(error-port, $stderr)
16
-
17
- section("Output"):
18
- doc"
19
- Write \hl{x to-s} to \hl{^output-port}, followed by a linebreak.
20
- " spec {
21
- => x
22
- } for {
23
- x print := x tap: ^output-port puts(x to-s)
24
- } examples:
25
- 1 print
26
- "hello" print
27
-
28
- doc"
29
- Write \hl{x to-s} to \hl{^output-port}.
30
- " spec {
31
- => x
32
- } for {
33
- x display := x tap: ^output-port send(#print, x to-s)
34
- } examples:
35
- 1 display
36
- "hello" display
37
-
38
- doc"
39
- Write \hl{x show} to \hl{^output-port}.
40
- " spec {
41
- => x
42
- } for {
43
- x write := x tap: ^output-port puts(x show)
44
- } examples:
45
- 1 write
46
- "hello" write
47
-
48
- doc"
49
- Set \hl{^output-port} to write output to \hl{filename} for the duration \
50
- of \hl{action}, ensuring that the file is closed.
51
-
52
- Returns the result of \hl{action}.
53
- " spec {
54
- filename is-a?(String)
55
- mode is-a?(String)
56
- => any
57
- } for {
58
- with-output-to((filename: String), mode = "w", &action) :=
59
- let(output-port = File open(filename, mode)):
60
- action ensuring:
61
- ^output-port close
62
- } examples:
63
- with-output-to("foo"):
64
- 42 print
65
-
66
- with-output-to("foo", "a"):
67
- "hello" print
68
-
69
- File open("foo", &#read)
70
-
71
- doc"
72
- Set \hl{^output-port} to write to \hl{io} for the duration of \hl{action}.
73
-
74
- Returns the result of \hl{action}.
75
- " spec {
76
- => any
77
- } for {
78
- with-output-to(io, &action) :=
79
- let(output-port = io, &action)
80
- } examples:
81
- require("stringio")
82
- x = StringIO new
83
- with-output-to(x):
84
- "hello!" write
85
- x string
86
-
87
- doc"
88
- Set \hl{^error-port} to write error output to \hl{filename} for the \
89
- duration of \hl{action}, ensuring that the file is closed.
90
-
91
- Returns the result of \hl{action}.
92
- " spec {
93
- filename is-a?(String)
94
- mode is-a?(String)
95
- => any
96
- } for {
97
- with-error-to((filename: String), mode = "w", &action) :=
98
- let(error-port = File open(filename, mode)):
99
- action ensuring:
100
- ^error-port close
101
- } examples:
102
- with-error-to("foo", "a"):
103
- warning(#some-warning)
104
-
105
- File open("foo", &#read)
106
-
107
- doc"
108
- Set \hl{^error-port} to write to \hl{io} for the duration of \hl{action}.
109
-
110
- Returns the result of \hl{action}.
111
- " spec {
112
- => any
113
- } for {
114
- with-error-to(io, &action) :=
115
- let(error-port = io, &action)
116
- } examples:
117
- require("stringio")
118
- x = StringIO new
119
-
120
- with-error-to(x):
121
- warning(#foo)
122
-
123
- x string
124
-
125
- section("Input"):
126
- doc"
127
- Read a line of text from \hl{^input-port}, signalling \hl{EndOfFile} on \
128
- end of file. Lines are separated by \hl{sep}. A separator of \hl{nil} \
129
- reads the entire contents, and a zero-length separator reads the input \
130
- one paragraph at a time (separated by two linebreaks).
131
- " spec {
132
- => String
133
- } for {
134
- read-line(sep = $separator) := do:
135
- x = ^input-port gets(sep)
136
-
137
- unless(x):
138
- error(EndOfFile new(^input-port))
139
-
140
- x
141
- } examples:
142
- with-input-from("foo"):
143
- read-line
144
-
145
- doc"
146
- Read all lines of text from \hl{^input-port}. Lines are separated by \
147
- \hl{sep}. A separator of \hl{nil} reads the entire contents as one \
148
- segment, and a zero-length separator reads the input one paragraph at a \
149
- time (separated by two linebreaks).
150
- " spec {
151
- => String
152
- } for {
153
- read-lines(sep = $separator) := do:
154
- x = ^input-port readlines(sep)
155
-
156
- unless(x):
157
- error(EndOfFile new(^input-port))
158
-
159
- x
160
- } examples:
161
- with-input-from("foo"):
162
- read-lines
163
-
164
- doc"
165
- Read a single byte from \hl{^input-port}, signalling \hl{EndOfFile} on \
166
- end of file.
167
- " spec {
168
- => Integer
169
- } for {
170
- read-byte := do:
171
- x = ^input-port getc
172
-
173
- unless(x):
174
- error(EndOfFile new(^input-port))
175
-
176
- x
177
- } examples:
178
- with-input-from("foo"):
179
- read-byte
180
-
181
- doc"
182
- Same as \hl{read-byte chr}.
183
- " spec {
184
- => String
185
- } for {
186
- read-char := read-byte chr
187
- } examples:
188
- with-input-from("foo"):
189
- read-char
190
-
191
- doc"
192
- Read at most \hl{length} bytes from \hl{^input-port}, or to the end of \
193
- file if \hl{length} is \hl{nil}. If \hl{buffer} is given, the data read \
194
- will be written to it.
195
- " spec {
196
- length nil? || length >= 0
197
- buffer nil? || buffer is-a?(String)
198
- => String || buffer || nil
199
- } for {
200
- read(length = nil, buffer = nil) :=
201
- ^input-port send(#read, length, buffer)
202
- } examples:
203
- x = ""
204
- with-input-from("foo"):
205
- read(10)
206
-
207
- with-input-from("foo"):
208
- read(10, x)
209
-
210
- x
211
-
212
- doc"
213
- Set \hl{^input-port} to read input from \hl{filename} for the duration \
214
- of \hl{action}, ensuring that the file is closed.
215
-
216
- Returns the result of \hl{action}.
217
- " spec {
218
- filename is-a?(String)
219
- mode is-a?(String)
220
- => any
221
- } for {
222
- with-input-from((filename: String), mode = "r", &action) :=
223
- let(input-port = File open(filename, mode)):
224
- action ensuring:
225
- ^input-port close
226
- } examples:
227
- with-input-from("foo"):
228
- read-line
229
-
230
- doc"
231
- Set \hl{^input-port} to write to \hl{io} for the duration of \hl{action}.
232
-
233
- Returns the result of \hl{action}.
234
- " spec {
235
- => any
236
- } for {
237
- with-input-from(io, &action) :=
238
- let(input-port = io, &action)
239
- } examples:
240
- require("stringio")
241
- x = StringIO new("hello\ngoodbye\n")
242
-
243
- with-input-from(x):
244
- read-line
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+
5
+ use(require("dynamic"))
6
+
7
+ const-set(.OutputPort, dynamic(STDOUT))
8
+ const-set(.InputPort, dynamic(STDIN))
9
+ const-set(.ErrorPort, dynamic(STDERR))
10
+
11
+ def(puts(x)): x tap: ^OutputPort puts(x)
12
+ def(print(x)): x tap: ^OutputPort print(x)
13
+
14
+ def(with-output-to(filename & String, mode = "w") &action):
15
+ with(OutputPort = File open(filename, mode)):
16
+ action ensuring:
17
+ ^OutputPort close
18
+
19
+ def(with-output-to(io) &action):
20
+ with(OutputPort = io):
21
+ action call
22
+
23
+ def(with-error-to(filename & String, mode = "w") &action):
24
+ with(ErrorPort = File open(filename, mode)):
25
+ action ensuring:
26
+ ^ErrorPort close
27
+
28
+ def(with-error-to(io) &action):
29
+ with(ErrorPort = io):
30
+ action call
31
+
32
+ macro($separator): '(Rubinius Globals [."$/"])
33
+
34
+ def(read-line(sep = $separator)):
35
+ x = ^InputPort gets(sep)
36
+
37
+ unless(x):
38
+ error(EndOfFile new(^InputPort))
39
+
40
+ x
41
+
42
+ def(read-lines(sep = $separator)):
43
+ x = ^InputPort readlines(sep)
44
+
45
+ unless(x):
46
+ error(EndOfFile new(^InputPort))
47
+
48
+ x
49
+
50
+ def(read-byte):
51
+ x = ^InputPort getc
52
+
53
+ unless(x):
54
+ error(EndOfFile new(^InputPort))
55
+
56
+ x
57
+
58
+ def(read-char): read-byte chr
59
+
60
+ def(read(length = nil, buffer = nil)):
61
+ ^InputPort read(length, buffer)
62
+
63
+ def(with-input-from(filename & String, mode = "r") &action):
64
+ with(InputPort = File open(filename, mode)):
65
+ action ensuring:
66
+ ^InputPort close
67
+
68
+ def(with-input-from(io) &action):
69
+ with(InputPort = io):
70
+ action call