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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62af6cac78961b06d75c20c9dc3ae90f7fca1fdd
4
- data.tar.gz: c0ac851cfa0bb9689b15f442767f9f0cdb8128ad
3
+ metadata.gz: eb2b96c8ce99460a0f0600c74786046f08607e3b
4
+ data.tar.gz: 275292c5f7ab03b089bcb7625b77f65e882db345
5
5
  SHA512:
6
- metadata.gz: 7749e039df36ab97e64a173178d3822a44aa0fe91b5a3dd236d5ad66e754c894c07c3cc1a6538466d9b92093e142aa8cf9b0f89e5b07749080b1afdfca9c93e1
7
- data.tar.gz: cdb16e0afc5cd0919b82679c5feb42706223e46d3534e3c5d7bdf779d35c1737f66020108d19806f5ee3eab4aabe2f37c40387001b7a9b1280d65b3a0b709621
6
+ metadata.gz: 8c56afef1d99fa1cb8e22c57dfe7a68520b09081a8699fac80293931a541ca751ab02cc852eef1e82dca3e5b8355cce4eaa2ce2deeb1fb30f30f47a50071f035
7
+ data.tar.gz: 6233206c5afa18e8aa828baa06fd8d9d5b96ecfb31a6aa66f74e6bd7c42dd28c2703aa435c44a2a292bd47ebc4ddbcd479899a3bc12bd69834d221ccc1d95dc8
@@ -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
@@ -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"
@@ -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 = evaluate_sequences(node, mod)
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
- res = evaluate_sequences(sub, mod)
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}")
@@ -1,3 +1,3 @@
1
1
  module Atomy
2
- VERSION = "0.6.4"
2
+ VERSION = "0.6.5"
3
3
  end
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
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-09 00:00:00.000000000 Z
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