atomy 0.6.4 → 0.6.5
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.
- checksums.yaml +4 -4
- data/kernel/format.ay +14 -0
- data/kernel/format/data.ay +56 -0
- data/kernel/format/formatter.ay +346 -0
- data/kernel/format/parser.ay +75 -0
- data/kernel/therie.ay +193 -0
- data/lib/atomy/codeloader.rb +75 -5
- data/lib/atomy/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb2b96c8ce99460a0f0600c74786046f08607e3b
|
4
|
+
data.tar.gz: 275292c5f7ab03b089bcb7625b77f65e882db345
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c56afef1d99fa1cb8e22c57dfe7a68520b09081a8699fac80293931a541ca751ab02cc852eef1e82dca3e5b8355cce4eaa2ce2deeb1fb30f30f47a50071f035
|
7
|
+
data.tar.gz: 6233206c5afa18e8aa828baa06fd8d9d5b96ecfb31a6aa66f74e6bd7c42dd28c2703aa435c44a2a292bd47ebc4ddbcd479899a3bc12bd69834d221ccc1d95dc8
|
data/kernel/format.ay
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
use(require("core"))
|
2
|
+
use(require("quotes"))
|
3
|
+
use(require("file"))
|
4
|
+
|
5
|
+
base = File expand-path("../", __FILE__)
|
6
|
+
|
7
|
+
Atomy const-set(.Format, Module new)
|
8
|
+
|
9
|
+
use(require(base + "/format/data"))
|
10
|
+
use(require(base + "/format/formatter"))
|
11
|
+
use(require(base + "/format/parser"))
|
12
|
+
|
13
|
+
macro-quoter(f) [c]:
|
14
|
+
Atomy Format Parser parse(c)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
use(require("core"))
|
2
|
+
use(require("define"))
|
3
|
+
use(require("array"))
|
4
|
+
use(require("control-flow"))
|
5
|
+
use(require("node"))
|
6
|
+
use(require("cosmetics"))
|
7
|
+
use(require("particles"))
|
8
|
+
|
9
|
+
Atomy Format open:
|
10
|
+
ast:
|
11
|
+
Segment:
|
12
|
+
Chunk([.flags], @text)
|
13
|
+
String([.flags])
|
14
|
+
Decimal([.flags])
|
15
|
+
Hex([.flags])
|
16
|
+
Octal([.flags])
|
17
|
+
Binary([.flags])
|
18
|
+
Radix([.flags])
|
19
|
+
Float([.flags])
|
20
|
+
Exponent([.flags])
|
21
|
+
General([.flags])
|
22
|
+
Character([.flags])
|
23
|
+
Any([.flags])
|
24
|
+
Pluralize(.singular, [.flags], .plural?)
|
25
|
+
Lowercase(.content, [.flags])
|
26
|
+
Capitalize(.content, [.flags])
|
27
|
+
Uppercase(.content, [.flags])
|
28
|
+
Justify([.segments], [.flags])
|
29
|
+
Skip([.flags])
|
30
|
+
Indirection([.flags])
|
31
|
+
Iterate(.content, [.flags])
|
32
|
+
Break([.flags])
|
33
|
+
Conditional([.branches], [.flags], .default?)
|
34
|
+
|
35
|
+
Flag:
|
36
|
+
Number(@value?)
|
37
|
+
Symbol(@character)
|
38
|
+
ZeroPad
|
39
|
+
Precision(@value)
|
40
|
+
|
41
|
+
Formatter([.segments])
|
42
|
+
|
43
|
+
Segment symbol(m)? :=
|
44
|
+
@flags any? [f]:
|
45
|
+
f match:
|
46
|
+
Symbol -> f character == m
|
47
|
+
_ -> false
|
48
|
+
|
49
|
+
Segment precision :=
|
50
|
+
@flags find .is-a(Precision)? ?value()
|
51
|
+
|
52
|
+
Segment zero-pad? :=
|
53
|
+
@flags any? [f]:
|
54
|
+
f match:
|
55
|
+
ZeroPad -> true
|
56
|
+
_ -> false
|
@@ -0,0 +1,346 @@
|
|
1
|
+
use("core")
|
2
|
+
use("define")
|
3
|
+
use("control-flow")
|
4
|
+
use("loop")
|
5
|
+
use("regexp")
|
6
|
+
use("particles")
|
7
|
+
use("patterns")
|
8
|
+
|
9
|
+
pretty = require("pretty")
|
10
|
+
|
11
|
+
|
12
|
+
Atomy Format open:
|
13
|
+
peek-input() = @input [@position]
|
14
|
+
|
15
|
+
next-input() =
|
16
|
+
peek-input tap:
|
17
|
+
@position += 1
|
18
|
+
|
19
|
+
next-inputs() = @input drop(@position) or []
|
20
|
+
|
21
|
+
pluralize(s) =
|
22
|
+
condition:
|
23
|
+
s =~ r"o$"(i) ->
|
24
|
+
s + "es"
|
25
|
+
|
26
|
+
s =~ r"[aeiou]$"(i) ->
|
27
|
+
s + "s"
|
28
|
+
|
29
|
+
s =~ r"(?<root>.+[aeiou])y$"(i) ->
|
30
|
+
s + "s"
|
31
|
+
|
32
|
+
s =~ r"(lay-by|stand-by)$"(i) ->
|
33
|
+
s + "s"
|
34
|
+
|
35
|
+
s =~ r"(.+)y$"(i) ->
|
36
|
+
$1 + "es"
|
37
|
+
|
38
|
+
s =~ r"(.+)us$"(i) ->
|
39
|
+
$1 + ""
|
40
|
+
|
41
|
+
s =~ r"(.+)sis$"(i) ->
|
42
|
+
$1 + "es"
|
43
|
+
|
44
|
+
s =~ r"(.+)(ex|ix)$"(i) ->
|
45
|
+
$1 + "ces"
|
46
|
+
|
47
|
+
s =~ r"(.+)(ss|sh|ch|dge)$"(i) ->
|
48
|
+
s + "es"
|
49
|
+
|
50
|
+
otherwise ->
|
51
|
+
s + "s"
|
52
|
+
|
53
|
+
sub-format(sub) = do:
|
54
|
+
sub position = @position
|
55
|
+
out = sub scan(*@input)
|
56
|
+
@position = sub position
|
57
|
+
sub reset!
|
58
|
+
out
|
59
|
+
|
60
|
+
iterate(f) =
|
61
|
+
until(next-inputs empty? or @stop?):
|
62
|
+
@output << sub-format(f)
|
63
|
+
|
64
|
+
iterate-max(max, f) =
|
65
|
+
max times:
|
66
|
+
when(next-inputs empty? or @stop?):
|
67
|
+
break
|
68
|
+
|
69
|
+
@output << sub-format(f)
|
70
|
+
|
71
|
+
number(s, default = 1) =
|
72
|
+
if(num = s flags find .is-a(Number)?)
|
73
|
+
then: num value or next-inputs size
|
74
|
+
else: default
|
75
|
+
|
76
|
+
next-number(s) =
|
77
|
+
number(s, nil) or next-input
|
78
|
+
|
79
|
+
justified(j, s, left? = false) =
|
80
|
+
if(w = number(j, nil))
|
81
|
+
then:
|
82
|
+
padding = if(j zero-pad?) then: "0"; else: " "
|
83
|
+
|
84
|
+
condition:
|
85
|
+
j symbol("=")? or j symbol("<")? and j symbol(">")? ->
|
86
|
+
s center(w, padding)
|
87
|
+
|
88
|
+
left? and not j symbol(">")? or j symbol("<")? ->
|
89
|
+
s ljust(w, padding)
|
90
|
+
|
91
|
+
otherwise ->
|
92
|
+
s rjust(w, padding)
|
93
|
+
else:
|
94
|
+
s
|
95
|
+
|
96
|
+
char(c, n: Integer) = justified(c, n chr, true)
|
97
|
+
char(c, s) = justified(c, s to-s [0, 1], true)
|
98
|
+
|
99
|
+
integer(i, base) = justified(i, Integer(next-input) to-s(base))
|
100
|
+
|
101
|
+
float(f, x) = do:
|
102
|
+
format =
|
103
|
+
if(f precision)
|
104
|
+
then: "%." + f precision to-s + x
|
105
|
+
else: "%" + x
|
106
|
+
|
107
|
+
justified(f, sprintf(format, Float(next-input)))
|
108
|
+
|
109
|
+
spaced(_, _, _, []) = ""
|
110
|
+
spaced(j, _, left, [s]) =
|
111
|
+
if(j symbol(">")? or j symbol("=")?)
|
112
|
+
then: s + " " * left
|
113
|
+
else: " " * left + s
|
114
|
+
spaced(j, average, left, s . ss) =
|
115
|
+
[ s
|
116
|
+
" " * average
|
117
|
+
spaced(j, average, left - average, ss)
|
118
|
+
] join
|
119
|
+
|
120
|
+
justify-to(_, _, []) = ""
|
121
|
+
justify-to(j, to, all: s . ss) = do:
|
122
|
+
needed = to - all collect .size inject .(+ _)
|
123
|
+
|
124
|
+
spacings =
|
125
|
+
condition:
|
126
|
+
j symbol("<")? and j symbol(">")? or j symbol("=")? ->
|
127
|
+
all size + 1
|
128
|
+
|
129
|
+
j symbol("<")? ->
|
130
|
+
all size
|
131
|
+
|
132
|
+
j symbol(">")? ->
|
133
|
+
all size
|
134
|
+
|
135
|
+
otherwise ->
|
136
|
+
all size - 1
|
137
|
+
|
138
|
+
naive-average = needed / spacings
|
139
|
+
|
140
|
+
average =
|
141
|
+
if(needed - naive-average * spacings >= spacings - 1)
|
142
|
+
then: naive-average + 1
|
143
|
+
else: naive-average
|
144
|
+
|
145
|
+
condition:
|
146
|
+
j symbol("<")? or j symbol("=")? ->
|
147
|
+
[ " " * naive-average
|
148
|
+
s
|
149
|
+
" " * average
|
150
|
+
spaced(j, average, needed - naive-average - average, ss)
|
151
|
+
] join
|
152
|
+
|
153
|
+
otherwise ->
|
154
|
+
[ s
|
155
|
+
" " * naive-average
|
156
|
+
spaced(j, average, needed - naive-average, ss)
|
157
|
+
] join
|
158
|
+
|
159
|
+
justify(j, [s]) = justified(j, s)
|
160
|
+
justify(j, ss) =
|
161
|
+
if(to = number(j, nil))
|
162
|
+
then: justify-to(j, to, ss)
|
163
|
+
else: ss join
|
164
|
+
|
165
|
+
|
166
|
+
process(c: Chunk) =
|
167
|
+
@output << c text
|
168
|
+
|
169
|
+
process(s: String) =
|
170
|
+
@output << justified(s, next-input to-s, true)
|
171
|
+
|
172
|
+
process(i: Decimal) =
|
173
|
+
@output << integer(i, 10)
|
174
|
+
|
175
|
+
process(i: Hex) =
|
176
|
+
@output << integer(i, 16)
|
177
|
+
|
178
|
+
process(i: Octal) =
|
179
|
+
@output << integer(i, 8)
|
180
|
+
|
181
|
+
process(i: Binary) =
|
182
|
+
@output << integer(i, 2)
|
183
|
+
|
184
|
+
process(i: Radix) =
|
185
|
+
@output << integer(i, i precision)
|
186
|
+
|
187
|
+
process(f: Float) =
|
188
|
+
@output << float(f, "f")
|
189
|
+
|
190
|
+
process(f: Exponent) =
|
191
|
+
@output << float(f, "e")
|
192
|
+
|
193
|
+
process(f: General) =
|
194
|
+
@output << float(f, "g")
|
195
|
+
|
196
|
+
process(c: Character) =
|
197
|
+
@output << char(c, next-input)
|
198
|
+
|
199
|
+
process(a: Any) =
|
200
|
+
@output << justified(a, pretty show(next-input), true)
|
201
|
+
|
202
|
+
process(p: Pluralize) = do:
|
203
|
+
num =
|
204
|
+
if(p symbol(">")?)
|
205
|
+
then: peek-input
|
206
|
+
else: next-input
|
207
|
+
|
208
|
+
@output <<
|
209
|
+
condition:
|
210
|
+
num == 1 ->
|
211
|
+
sub-format(p singular)
|
212
|
+
|
213
|
+
p plural ->
|
214
|
+
sub-format(p plural)
|
215
|
+
|
216
|
+
otherwise ->
|
217
|
+
pluralize(sub-format(p singular))
|
218
|
+
|
219
|
+
process(l: Lowercase) =
|
220
|
+
@output << sub-format(l content) downcase
|
221
|
+
|
222
|
+
process(c: Capitalize) = do:
|
223
|
+
words = sub-format(c content) split(" ")
|
224
|
+
number(c, words size) times [n]:
|
225
|
+
unless(n == 0):
|
226
|
+
@output << " "
|
227
|
+
|
228
|
+
@output << words shift capitalize
|
229
|
+
|
230
|
+
unless(words empty?):
|
231
|
+
@output << " " + words join(" ")
|
232
|
+
|
233
|
+
process(u: Uppercase) =
|
234
|
+
@output << sub-format(u content) upcase
|
235
|
+
|
236
|
+
process(s: Skip) =
|
237
|
+
if(s symbol("<")?)
|
238
|
+
then: @position -= number(s)
|
239
|
+
else: @position += number(s)
|
240
|
+
|
241
|
+
process(i: Indirection) =
|
242
|
+
@output <<
|
243
|
+
if(i symbol("*")?)
|
244
|
+
then: sub-format(next-input)
|
245
|
+
else: next-input format(*next-input)
|
246
|
+
|
247
|
+
process(i: Iterate) = do:
|
248
|
+
splat? = i symbol("*")?
|
249
|
+
sub? = i symbol(".")?
|
250
|
+
always-run? = i symbol("+")?
|
251
|
+
iterations = number(i, nil)
|
252
|
+
|
253
|
+
inputs =
|
254
|
+
if(splat?)
|
255
|
+
then: next-inputs
|
256
|
+
else: next-input
|
257
|
+
|
258
|
+
before = [@input, @position]
|
259
|
+
|
260
|
+
when(inputs empty? and always-run? and
|
261
|
+
iterations != 0):
|
262
|
+
@output << sub-format(i content)
|
263
|
+
return(nil)
|
264
|
+
|
265
|
+
condition:
|
266
|
+
iterations:
|
267
|
+
@input = inputs
|
268
|
+
@position = 0
|
269
|
+
iterate-max(iterations, i content)
|
270
|
+
|
271
|
+
sub?:
|
272
|
+
@iterating = inputs
|
273
|
+
inputs each [is]:
|
274
|
+
@output << i content format(*is)
|
275
|
+
|
276
|
+
otherwise:
|
277
|
+
@input = inputs
|
278
|
+
@position = 0
|
279
|
+
iterate(i content)
|
280
|
+
|
281
|
+
if(splat?)
|
282
|
+
then: @position = @input size
|
283
|
+
else: [@input, @position] = before
|
284
|
+
|
285
|
+
process(c: Conditional) =
|
286
|
+
[c symbol("?")?, c branches] match:
|
287
|
+
[true, t . (f . _)] ->
|
288
|
+
@output << sub-format(if(next-input) then: t; else: f)
|
289
|
+
|
290
|
+
[true, [t]] ->
|
291
|
+
when(next-input):
|
292
|
+
@output << sub-format(t)
|
293
|
+
|
294
|
+
_:
|
295
|
+
n = next-number(c)
|
296
|
+
if(n >= c branches size)
|
297
|
+
then:
|
298
|
+
when(c default):
|
299
|
+
@output << sub-format(c default)
|
300
|
+
else:
|
301
|
+
@output << sub-format(c branches [n])
|
302
|
+
|
303
|
+
process(j: Justify) =
|
304
|
+
@output <<
|
305
|
+
justify(j, j segments collect [s]: sub-format(s))
|
306
|
+
|
307
|
+
process(x) = raise("todo formatting: " + x inspect)
|
308
|
+
|
309
|
+
Formatter open:
|
310
|
+
attr-accessor(.position)
|
311
|
+
|
312
|
+
initialize(opts = nil) &blk := do:
|
313
|
+
super(opts) &blk
|
314
|
+
reset!
|
315
|
+
|
316
|
+
bytecode(g, mod) := do:
|
317
|
+
pos(g)
|
318
|
+
construct(g, mod)
|
319
|
+
|
320
|
+
reset! := do:
|
321
|
+
@input = []
|
322
|
+
@output = ""
|
323
|
+
@position = 0
|
324
|
+
@stop? = false
|
325
|
+
@iterating = []
|
326
|
+
|
327
|
+
scan(*@input) := do:
|
328
|
+
@segments each [s]:
|
329
|
+
s match:
|
330
|
+
Break ? symbol(".")? ->
|
331
|
+
when(@iterating empty?):
|
332
|
+
@stop? = true
|
333
|
+
break
|
334
|
+
|
335
|
+
Break ->
|
336
|
+
when(next-inputs empty?):
|
337
|
+
break
|
338
|
+
|
339
|
+
_ -> process(s)
|
340
|
+
|
341
|
+
@output
|
342
|
+
|
343
|
+
format(*inputs) :=
|
344
|
+
scan(*inputs) tap: reset!
|
345
|
+
|
346
|
+
alias-method(.[], .format)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
use("core")
|
2
|
+
use("define")
|
3
|
+
use("block")
|
4
|
+
use("control-flow")
|
5
|
+
use("grammar")
|
6
|
+
use("init")
|
7
|
+
|
8
|
+
Atomy Format open:
|
9
|
+
parser(Parser):
|
10
|
+
%atomy := Atomy Parser
|
11
|
+
|
12
|
+
text(e) := [
|
13
|
+
<(/"[^\\%#{Regexp quote(e)}]+"/)> { text }
|
14
|
+
"\\" <(/"[%\(\)\{\}\[\]]"/)> { text }
|
15
|
+
"\\" e=(%atomy(escape)) { e }
|
16
|
+
]
|
17
|
+
|
18
|
+
nested(e) := c=(text(e)+) { init(Chunk, text: c join) }
|
19
|
+
|
20
|
+
chunk := nested("")
|
21
|
+
|
22
|
+
flagged := "%" fs=(flag*) s=(segment) { s flags = fs, s }
|
23
|
+
|
24
|
+
flag := [
|
25
|
+
"#" { Number new }
|
26
|
+
"0" &("." /"\d"/ | /"\d"/) { ZeroPad new }
|
27
|
+
"." <(/"\d+"/)> { init(Precision, value: text to-i) }
|
28
|
+
<(/"\d+"/)> { init(Number, value: text to-i) }
|
29
|
+
<(/"[\.\+\*=<>,\?]"/)> { init(Symbol, character: text) }
|
30
|
+
]
|
31
|
+
|
32
|
+
segment := [
|
33
|
+
"p" "(" s=(sub(")")) ")" ("(" p=(sub(")")) ")")? {
|
34
|
+
Pluralize new [n]:
|
35
|
+
n singular = s
|
36
|
+
n plural = p
|
37
|
+
}
|
38
|
+
"l" "(" c=(sub(")")) ")" { init(Lowercase, content: c) }
|
39
|
+
"c" "(" c=(sub(")")) ")" { init(Capitalize, content: c) }
|
40
|
+
"u" "(" c=(sub(")")) ")" { init(Uppercase, content: c) }
|
41
|
+
"j" cs=(("(" c=(sub(")")) ")" { c })+) { init(Justify, segments: cs) }
|
42
|
+
"{" c=(sub("}")) "}" { init(Iterate, content: c) }
|
43
|
+
bs=(("[" c=(sub("]")) "]" { c })+) ("(" d=(sub(")")) ")")? {
|
44
|
+
init(Conditional, branches -> Array(bs), default -> d)
|
45
|
+
}
|
46
|
+
"_" { Skip new }
|
47
|
+
"^" { Break new }
|
48
|
+
"%" { Indirection new }
|
49
|
+
"s" { String new }
|
50
|
+
"d" { Decimal new }
|
51
|
+
"x" { Hex new }
|
52
|
+
"o" { Octal new }
|
53
|
+
"b" { Binary new }
|
54
|
+
"r" { Radix new }
|
55
|
+
"f" { Float new }
|
56
|
+
"e" { Exponent new }
|
57
|
+
"g" { General new }
|
58
|
+
"c" { Character new }
|
59
|
+
"v" { Any new }
|
60
|
+
]
|
61
|
+
|
62
|
+
sub(e) := as=((flagged | nested(e))*) {
|
63
|
+
init(Formatter, segments -> Array(as))
|
64
|
+
}
|
65
|
+
|
66
|
+
root := x=(sub("")) !(/"."/) { x }
|
67
|
+
|
68
|
+
|
69
|
+
Parser singleton:
|
70
|
+
parse(source) :=
|
71
|
+
new(source) onto:
|
72
|
+
unless(parse):
|
73
|
+
raise-error
|
74
|
+
|
75
|
+
result
|
data/kernel/therie.ay
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
use(require("atomy"))
|
2
|
+
|
3
|
+
io = require("io")
|
4
|
+
|
5
|
+
nesting-level = dynamic(0)
|
6
|
+
running-stats = dynamic
|
7
|
+
|
8
|
+
data(Stats(@passed = 0, @failed = 0))
|
9
|
+
|
10
|
+
fn(indented(s)): (" " * (^nesting-level * 2)) + s
|
11
|
+
|
12
|
+
fn(colored(color, s)):
|
13
|
+
unless(^(io OutputPort) tty?):
|
14
|
+
return(s)
|
15
|
+
|
16
|
+
codes = [
|
17
|
+
.black
|
18
|
+
.red
|
19
|
+
.green
|
20
|
+
.yellow
|
21
|
+
.blue
|
22
|
+
.magenta
|
23
|
+
.cyan
|
24
|
+
.white
|
25
|
+
]
|
26
|
+
|
27
|
+
i"\e[3#{codes index(color)}m#{s}\e[0m"
|
28
|
+
|
29
|
+
fn(in-own-module &action):
|
30
|
+
ctx = Atomy Module new
|
31
|
+
ctx use(self)
|
32
|
+
ctx module-exec &action
|
33
|
+
|
34
|
+
|
35
|
+
def(theorize &tests):
|
36
|
+
with(running-stats = Stats new):
|
37
|
+
tests call
|
38
|
+
puts("")
|
39
|
+
|
40
|
+
stats = ^running-stats
|
41
|
+
|
42
|
+
puts(
|
43
|
+
f"total of %d tests (%s passed, %s failed)" [
|
44
|
+
stats failed + stats passed
|
45
|
+
colored(.green, stats passed)
|
46
|
+
if(stats failed == 0)
|
47
|
+
then: "0"
|
48
|
+
else: colored(.red, stats failed)
|
49
|
+
])
|
50
|
+
|
51
|
+
stats
|
52
|
+
|
53
|
+
|
54
|
+
def(describe(what) &body):
|
55
|
+
puts(indented(f"- %s" [what]))
|
56
|
+
|
57
|
+
with(nesting-level = (^nesting-level + 1)):
|
58
|
+
in-own-module &body
|
59
|
+
|
60
|
+
nil
|
61
|
+
|
62
|
+
alias-method(.context, .describe)
|
63
|
+
|
64
|
+
|
65
|
+
def(let(name) &body):
|
66
|
+
define-method(name):
|
67
|
+
res = instance-exec &body
|
68
|
+
|
69
|
+
singleton:
|
70
|
+
define-method(name): res
|
71
|
+
|
72
|
+
res
|
73
|
+
|
74
|
+
def(subject &body): def(.subject) &body
|
75
|
+
|
76
|
+
|
77
|
+
def(it(description) &tests):
|
78
|
+
do {
|
79
|
+
in-own-module &tests
|
80
|
+
puts(indented(colored(.green, f"✓ %s" [description])))
|
81
|
+
} rescue {
|
82
|
+
e:
|
83
|
+
when(^running-stats):
|
84
|
+
^running-stats failed += 1
|
85
|
+
|
86
|
+
puts(indented(colored(.red, f"✗ %s" [description])))
|
87
|
+
puts(
|
88
|
+
indented(
|
89
|
+
colored(
|
90
|
+
.yellow
|
91
|
+
f" ` %s: %s" [
|
92
|
+
e class name
|
93
|
+
e message
|
94
|
+
])))
|
95
|
+
|
96
|
+
e backtrace first((ENV["THERIE_BT_LIMIT"] or 5) to-i) each [l]:
|
97
|
+
puts(indented(f" %s" [colored(.cyan, l)]))
|
98
|
+
} else:
|
99
|
+
when(^running-stats):
|
100
|
+
^running-stats passed += 1
|
101
|
+
|
102
|
+
nil
|
103
|
+
|
104
|
+
|
105
|
+
data(Actuality(@value = nil, @action = nil))
|
106
|
+
|
107
|
+
def(expect(value)): Actuality new(value)
|
108
|
+
def(expect &action): Actuality new(nil, action)
|
109
|
+
|
110
|
+
def(Actuality to): ExpectTo new(self)
|
111
|
+
def(Actuality to-not): ExpectTo new(self, true)
|
112
|
+
|
113
|
+
|
114
|
+
data(ExpectTo(@actual, @negated? = false))
|
115
|
+
|
116
|
+
def(ExpectTo(actual, negated) match(matcher)):
|
117
|
+
matched = matcher matches?(actual)
|
118
|
+
|
119
|
+
condition:
|
120
|
+
negated && matched:
|
121
|
+
/raise(matcher negative-failure-message(actual))
|
122
|
+
|
123
|
+
negated && !matched:
|
124
|
+
true
|
125
|
+
|
126
|
+
!matched:
|
127
|
+
/raise(matcher failure-message(actual))
|
128
|
+
|
129
|
+
negated:
|
130
|
+
true
|
131
|
+
|
132
|
+
|
133
|
+
data(Matcher)
|
134
|
+
|
135
|
+
def(Matcher matches?(actual)): /error(.not-implemented)
|
136
|
+
def(Matcher failure-message(actual)): /error(.not-implemented)
|
137
|
+
def(Matcher negative-failure-message(actual)): /error(.not-implemented)
|
138
|
+
|
139
|
+
Matcher data: EqualityMatcher(@value)
|
140
|
+
def(ExpectTo be(value)): match(EqualityMatcher new(value))
|
141
|
+
def(EqualityMatcher(value) matches?(actual)): actual value == value
|
142
|
+
def(EqualityMatcher(value) failure-message(actual)):
|
143
|
+
i"expected #{actual value} to be #{value}"
|
144
|
+
def(EqualityMatcher(value) negative-failure-message(actual)):
|
145
|
+
i"expected #{actual value} to not be #{value}, but it was"
|
146
|
+
|
147
|
+
|
148
|
+
Matcher data: RaiseMatcher(@exception, @message = nil)
|
149
|
+
def(ExpectTo raise(exception, message = nil)):
|
150
|
+
match(RaiseMatcher new(exception, message))
|
151
|
+
def(RaiseMatcher matches?(actual)):
|
152
|
+
actual action rescue {
|
153
|
+
e:
|
154
|
+
@raised = e
|
155
|
+
@raised is-a?(@exception)
|
156
|
+
} else: false
|
157
|
+
def(RaiseMatcher failure-message(actual)):
|
158
|
+
if(@raised)
|
159
|
+
then: i"expected #{@exception}, got #{@raised class}: #{@raised}"
|
160
|
+
else: i"expected #{@exception} but nothing was raised"
|
161
|
+
def(RaiseMatcher negative-failure-message(actual)):
|
162
|
+
i"expected #{@exception} to not be raised, but it was"
|
163
|
+
|
164
|
+
|
165
|
+
Matcher data: ErrorMatcher(@error)
|
166
|
+
def(ExpectTo error(error)): match(ErrorMatcher new(error))
|
167
|
+
def(ErrorMatcher matches?(actual)):
|
168
|
+
with-restarts(errored(matched?) -> matched?) {
|
169
|
+
actual action call
|
170
|
+
false
|
171
|
+
} bind {
|
172
|
+
(e: ExceptionError):
|
173
|
+
raise(e exception)
|
174
|
+
|
175
|
+
(e: Error):
|
176
|
+
@errored = e
|
177
|
+
/restart(.errored, e kind-of?(@error))
|
178
|
+
}
|
179
|
+
def(ErrorMatcher failure-message(actual)):
|
180
|
+
if(@errored)
|
181
|
+
then: i"expected #{@error}, got #{@errored class}: #{@errored}"
|
182
|
+
else: i"expected #{@error} but nothing was signalled"
|
183
|
+
def(ErrorMatcher negative-failure-message(actual)):
|
184
|
+
i"expected #{@error} to not be signalled, but it was"
|
185
|
+
|
186
|
+
|
187
|
+
Matcher data: KindMatcher(@class)
|
188
|
+
def(ExpectTo be-a(class)): match(KindMatcher new(class))
|
189
|
+
def(KindMatcher matches?(actual)): actual value is-a?(@class)
|
190
|
+
def(KindMatcher failure-message(actual)):
|
191
|
+
i"expected #{actual value} (#{actual value class}) to be a #{@class}"
|
192
|
+
def(KindMatcher negative-failure-message(actual)):
|
193
|
+
i"expected #{actual value} (#{actual value class}) to not be a #{@class}, but it was"
|
data/lib/atomy/codeloader.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
1
3
|
require "atomy/bootstrap"
|
2
4
|
require "atomy/compiler"
|
3
5
|
require "atomy/parser"
|
4
6
|
require "atomy/module"
|
5
7
|
|
8
|
+
require "rubinius/compiler"
|
9
|
+
require "rubinius/compiler/compiled_file"
|
10
|
+
|
6
11
|
module Atomy
|
7
12
|
module CodeLoader
|
8
13
|
LOADED_MODULES = {}
|
@@ -143,24 +148,55 @@ module Atomy
|
|
143
148
|
mod = Atomy::Module.new { use(Atomy::Bootstrap) }
|
144
149
|
mod.file = file.to_sym
|
145
150
|
|
151
|
+
compiled_file_name = CodeTools::Compiler.compiled_name(file)
|
152
|
+
if should_load_compiled_file(compiled_file_name, file)
|
153
|
+
code_loader = Rubinius::CodeLoader.new(compiled_file_name)
|
154
|
+
code = code_loader.load_compiled_file(compiled_file_name, 0, 0)
|
155
|
+
|
156
|
+
Rubinius.attach_method(
|
157
|
+
:__script__,
|
158
|
+
code,
|
159
|
+
mod.compile_context.constant_scope,
|
160
|
+
mod)
|
161
|
+
|
162
|
+
res = mod.__script__
|
163
|
+
|
164
|
+
return [res, mod]
|
165
|
+
end
|
166
|
+
|
146
167
|
node = Atomy::Parser.parse_file(file)
|
147
168
|
|
148
|
-
res =
|
169
|
+
res = nil
|
170
|
+
code =
|
171
|
+
Atomy::Compiler.package(mod.file) do |gen|
|
172
|
+
res = evaluate_sequences(gen, node, mod)
|
173
|
+
end
|
174
|
+
|
175
|
+
if ENV["DEBUG"]
|
176
|
+
printer = CodeTools::Compiler::MethodPrinter.new
|
177
|
+
printer.bytecode = true
|
178
|
+
printer.print_method(code)
|
179
|
+
end
|
180
|
+
|
181
|
+
write_compiled_file(compiled_file_name, mod, code) if compiled_file_name
|
149
182
|
|
150
183
|
[res, mod]
|
151
184
|
end
|
152
185
|
|
153
|
-
def evaluate_sequences(n, mod)
|
186
|
+
def evaluate_sequences(gen, n, mod)
|
154
187
|
if n.is_a?(Atomy::Grammar::AST::Sequence)
|
155
188
|
res = nil
|
156
189
|
|
157
|
-
n.nodes.each do |sub|
|
158
|
-
|
190
|
+
n.nodes.each.with_index do |sub, i|
|
191
|
+
gen.pop unless i == 0
|
192
|
+
res = evaluate_sequences(gen, sub, mod)
|
159
193
|
end
|
160
194
|
|
161
195
|
res
|
162
196
|
else
|
163
|
-
mod.evaluate(n, mod.compile_context)
|
197
|
+
res = mod.evaluate(n, mod.compile_context)
|
198
|
+
mod.compile(gen, n)
|
199
|
+
res
|
164
200
|
end
|
165
201
|
end
|
166
202
|
|
@@ -191,6 +227,40 @@ module Atomy
|
|
191
227
|
".ay"
|
192
228
|
end
|
193
229
|
|
230
|
+
def should_load_compiled_file(compiled_file, source_file)
|
231
|
+
return false unless compiled_file
|
232
|
+
return false unless File.exists?(compiled_file)
|
233
|
+
|
234
|
+
compiled_mtime = File.mtime(compiled_file)
|
235
|
+
return false if File.mtime(source_file) > compiled_mtime
|
236
|
+
|
237
|
+
module_list_file_name = compiled_file + ".modules"
|
238
|
+
if File.exists?(module_list_file_name)
|
239
|
+
File.open(module_list_file_name, "r") do |io|
|
240
|
+
io.each_line do |line|
|
241
|
+
mod_file = line.rstrip
|
242
|
+
return false if File.mtime(mod_file) > compiled_mtime
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
250
|
+
def write_compiled_file(compiled_file_name, mod, code)
|
251
|
+
FileUtils.mkdir_p(File.expand_path("../", compiled_file_name))
|
252
|
+
CodeTools::CompiledFile.dump(code, compiled_file_name, Rubinius::Signature, 0)
|
253
|
+
|
254
|
+
module_list_file_name = compiled_file_name + ".modules"
|
255
|
+
File.open(module_list_file_name, "w") do |io|
|
256
|
+
mod.singleton_class.included_modules.each do |used_module|
|
257
|
+
next if used_module == mod
|
258
|
+
next unless used_module.is_a?(Atomy::Module) && used_module.file
|
259
|
+
io.puts(used_module.file.to_s)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
194
264
|
def search_path(path, load_paths)
|
195
265
|
load_paths.each do |load_path|
|
196
266
|
if found = find_source("#{load_path}/#{path}")
|
data/lib/atomy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: atomy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Suraci
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kpeg
|
@@ -101,6 +101,10 @@ files:
|
|
101
101
|
- kernel/doc.ay
|
102
102
|
- kernel/dynamic.ay
|
103
103
|
- kernel/file.ay
|
104
|
+
- kernel/format.ay
|
105
|
+
- kernel/format/data.ay
|
106
|
+
- kernel/format/formatter.ay
|
107
|
+
- kernel/format/parser.ay
|
104
108
|
- kernel/grammar.ay
|
105
109
|
- kernel/hash.ay
|
106
110
|
- kernel/interpolation.ay
|
@@ -117,6 +121,7 @@ files:
|
|
117
121
|
- kernel/regexp.ay
|
118
122
|
- kernel/repl.ay
|
119
123
|
- kernel/stack-local.ay
|
124
|
+
- kernel/therie.ay
|
120
125
|
- lib/atomy.rb
|
121
126
|
- lib/atomy/bootstrap.rb
|
122
127
|
- lib/atomy/code/assign.rb
|