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/quotes.ay ADDED
@@ -0,0 +1,29 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+
5
+ macro(macro-quoter(~n) [~*as]: ~*body):
6
+ strpat = Unquote new('(string-literal & StringLiteral))
7
+ argpat = Unquote new('*args)
8
+
9
+ `({
10
+ quoter = [~*as]: ~*body
11
+
12
+ macro(~n ~strpat):
13
+ quoter call(string-literal value, [], evaluate(string-literal))
14
+
15
+ macro(~n (~strpat)(~argpat)):
16
+ quoter call(string-literal value, args collect &.text, evaluate(string-literal))
17
+ } call)
18
+
19
+
20
+ macro-quoter(w) [_, _, v]:
21
+ `[~*(v split collect [s]: Atomy Grammar AST StringLiteral new(s))]
22
+
23
+ macro-quoter(s) [_, _, v]:
24
+ `[~*(v split collect [s]:
25
+ if(s =~ Regexp new("[\p{Ll}_]", Regexp KCODE_UTF8))
26
+ then: `.~(Atomy Grammar AST Word new(s tr("-", "_") to-sym))
27
+ else: `.~(Atomy Grammar AST Word new(s to-sym)))]
28
+
29
+ macro-quoter(raw) [r]: Atomy Code StringLiteral new(r, true)
data/kernel/range.ay ADDED
@@ -0,0 +1,4 @@
1
+ use(require("core"))
2
+
3
+ macro(~a .. ~b): `(//Range new(~a, ~b))
4
+ macro(~a ... ~b): `(//Range new(~a, ~b, true))
data/kernel/regexp.ay ADDED
@@ -0,0 +1,23 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("quotes"))
4
+ use(require("control-flow"))
5
+ use(require("mutation"))
6
+ interpolate = require("interpolation")
7
+
8
+ macro-quoter(r) [r, fs]:
9
+ flags = 0
10
+
11
+ when(fs include?(.m)):
12
+ flags |= Regexp MULTILINE
13
+
14
+ when(fs include?(.i)):
15
+ flags |= Regexp IGNORECASE
16
+
17
+ when(fs include?(.x)):
18
+ flags |= Regexp EXTENDED
19
+
20
+ -- UTF8 by default
21
+ flags |= Regexp KCODE_UTF8
22
+
23
+ `(//Regexp new(~(interpolate interpolated(r)), ~(Atomy Grammar AST Number new(flags))))
data/kernel/repl.ay CHANGED
@@ -1,140 +1,114 @@
1
- namespace(atomy)
1
+ use(require("atomy"))
2
2
 
3
- title"The REPL"
3
+ use(require("doc"))
4
+ condition = use(require("condition"))
5
+ pretty = require("pretty")
4
6
 
5
7
  require("readline")
6
8
 
7
- doc"
8
- The basics of a REPL - reading, evaluating, and printing in a loop. More \
9
- flexibility is provided by various signals. See \hl{repl} for a fancier \
10
- REPL, which builds upon this, and \hl{ReplDebugger}.
11
-
12
- When showing the prompt, \hl{#prompt} is signaled with a \hl{#use-prompt} \
13
- restart available. Invoke this restart and pass along a string to \
14
- override the prompt, which defaults to \code{>>}.
9
+ fn(try(source, module, debug = false)):
10
+ with-restarts(
11
+ retry: try(source, module)
12
+ abort: .ok):
13
+ condition signal(.evaluated(module evaluate(Atomy Parser parse-string(source), module compile-context))) rescue:
14
+ (e & (StandardError | ScriptError)): error(e)
15
15
 
16
- Input preceded by a colon (\code{:}) and followed by an alphanumeric \
17
- character is assumed to be a \italic{special command}. These are not \
18
- evaluated, and are signaled as \hl{#special(\italic{text})}.
16
+ fn(basic-repl(module, debug = false)):
17
+ loop:
18
+ prompt =
19
+ with-restarts(use-prompt(p): p):
20
+ condition signal(.prompt)
21
+ ">> "
19
22
 
20
- When the user sends \code{EOF} (Ctrl+D) or an interrupt (Ctrl+C), \
21
- \hl{#quit} is signaled.
22
-
23
- When the user enters code, \hl{#input(\italic{text})} is signaled. The code\
24
- is evaluated with two restarts registered: \code{#retry} for re-attempting \
25
- evaluation, and \code{#abort}, for canceling the evaluation. After the code\
26
- is evaluated, \hl{#evaluated(\italic{result})} is signaled.
23
+ input =
24
+ Readline readline(prompt, true) rescue:
25
+ Interrupt: condition signal(.quit), ""
27
26
 
28
- \hl{#loop} is signaled before the loop starts over again (i.e., after the \
29
- input is handled).
30
- " spec {
31
- bnd is-a?(Binding)
32
- } for:
33
- basic-repl(bnd = TOPLEVEL_BINDING) :=
34
- loop:
35
- prompt =
36
- with-restarts(use-prompt(p) -> p):
37
- signal(#prompt)
38
- ">> "
27
+ input match:
28
+ nil: condition signal(.quit)
39
29
 
40
- in =
41
- { Readline readline(prompt)
42
- } rescue:
43
- Interrupt -> do { signal(#quit), "" }
30
+ "": .ok
44
31
 
45
- in match:
46
- nil -> signal(#quit)
32
+ (String & { =~ r"^:[[:alnum:]]" }):
33
+ condition signal(.special(input[1 .. -1]))
47
34
 
48
- "" -> #ok
35
+ source:
36
+ condition signal(.input(source))
37
+ try(source, module, debug)
49
38
 
50
- String ? (=~ r"^:[[:alnum:]]") ->
51
- signal(#special(in [1 .. -1]))
39
+ condition signal(.loop)
52
40
 
53
- source -> do:
54
- signal(#input(source))
55
41
 
56
- try = {
57
- with-restarts(retry -> try [], abort -> #ok):
58
- res = Atomy::Compiler evaluate(source, bnd)
59
- signal(#evaluated(res))
60
- }
42
+ condition DefaultDebugger data(ReplDebugger(@error))
61
43
 
62
- try []
44
+ ReplDebugger open:
45
+ attr-accessor(.module)
63
46
 
64
- signal(#loop)
47
+ def(ReplDebugger run):
48
+ condition signal(.debug(self))
65
49
 
50
+ show-banner
66
51
 
67
- doc"
68
- An interactive debugger REPL for handling errors. This will list the \
69
- results along with a number, allow the user to continue evaluating code, \
70
- and once they enter a \italic{special command} in the form of \
71
- \code{:\italic{number}}, the specified restart will be invoked.
72
- " for:
73
- class(ReplDebugger):
74
- class(<< self):
75
- show-backtrace(e) := do:
76
- Rubinius::Backtrace backtrace(e backtrace) _/show print
77
- debug(e)
52
+ with-restarts(backtrace: show-backtrace):
53
+ debug
78
54
 
79
- run(e) := do:
80
- DefaultDebugger show-error-banner(e)
55
+ def(ReplDebugger(e) show-banner):
56
+ puts("-" * 78)
57
+ i"#{e name}: #{e message}" split("\n") each [l]:
58
+ puts(i"*** #{l}")
81
59
 
82
- with-restarts(backtrace -> show-backtrace(e)):
83
- debug(e)
60
+ def(ReplDebugger debug):
61
+ show-restarts
84
62
 
85
- debug(e) := do:
86
- DefaultDebugger show-options-for(e)
63
+ basic-repl(@module) bind:
64
+ .prompt: condition restart(.use-prompt, "[!]> ")
87
65
 
88
- { basic-repl } bind:
89
- #prompt -> restart(#use-prompt, "[!]> ")
66
+ .special(n & { =~ r"\d+" }):
67
+ ^(condition Restarts) [n to-i] invoke
90
68
 
91
- #special(n ? (=~ r"\d+")) ->
92
- ^restarts [n to-i] invoke
69
+ .quit: exit(1)
93
70
 
94
- #quit -> exit(1)
95
71
 
96
- dynamic(debugger, ReplDebugger)
72
+ def(repl(history = nil, module = nil, debug = false)):
73
+ unless(module):
74
+ &module = Atomy Module new
75
+ module file = ."(repl)"
76
+ module use(require("atomy"))
97
77
 
98
- doc"
99
- A more feature-filled REPL, providing persistent history and setting \
100
- \hl{^debugger} to \hl{ReplDebugger}.
78
+ when(history && File exists?(history)):
79
+ File open(history, "r") [f]:
80
+ f readlines each [l]:
81
+ Readline HISTORY << l strip
101
82
 
102
- History will be managed and appended to a file specified by \hl{history} \
103
- upon termination.
104
- " spec {
105
- history is-a?(String)
106
- bnd is-a?(Binding)
107
- } for:
108
- repl(history = nil, bnd = TOPLEVEL_BINDING) := do:
109
- when(history && File exists?(history)):
110
- File open(history, "r") [f]:
111
- f readlines each [l]:
112
- Readline::HISTORY << l strip
113
-
114
- SANE_HISTORY = []
83
+ sane-history = []
115
84
 
116
- { let(debugger = ReplDebugger):
117
- frame = 0
85
+ with(condition Debugger = ReplDebugger) {
86
+ frame = 0
118
87
 
119
- { let(atomy/pretty/colored? = true):
120
- basic-repl(bnd)
121
- } bind:
122
- #prompt ->
123
- restart(#use-prompt, "[" + frame to-s + "]> ")
124
-
125
- #loop ->
126
- (frame += 1)
88
+ basic-repl(module, debug) bind:
89
+ .prompt:
90
+ restart(.use-prompt, i"[#{frame}]> ")
127
91
 
128
- #quit -> exit(0)
129
-
130
- #input(str) -> (SANE_HISTORY << str)
92
+ .loop:
93
+ frame += 1
131
94
 
132
- #special("h") ->
133
- ":h\thelp" print
95
+ .quit:
96
+ exit(0)
134
97
 
135
- #evaluated(r) ->
136
- (" => " + r show) print
137
- } ensuring:
138
- when(history):
139
- File open(history, "a") [f]:
140
- f puts(*SANE_HISTORY)
98
+ .input(str):
99
+ sane-history << str
100
+
101
+ .special(String & { == "h" }):
102
+ puts(":h\thelp")
103
+
104
+ .debug(dbg):
105
+ dbg module = module
106
+
107
+ .evaluated(r):
108
+ with(pretty Multiline = true,
109
+ pretty Colored = true):
110
+ puts((text(" =>") <+> pretty doc(r)) render(56))
111
+ } ensuring:
112
+ when(history):
113
+ File open(history, "a") [f]:
114
+ f puts(*sane-history)
@@ -0,0 +1,21 @@
1
+ use(require("core"))
2
+ use(require("define"))
3
+ use(require("control-flow"))
4
+ use(require("patterns"))
5
+
6
+ class(Local):
7
+ class(Setter):
8
+ def(initialize(@local, @code)) {}
9
+
10
+ def(bytecode(gen, mod)):
11
+ mod compile(gen, @code)
12
+ gen set-stack-local(@local allocate(gen))
13
+
14
+ def(bytecode(gen, mod)):
15
+ gen push-stack-local(allocate(gen))
16
+
17
+ def(allocate(gen)):
18
+ @stack-local = (@stack-local || gen new-stack-local)
19
+
20
+ def(set(code)):
21
+ Setter new(self, code)
data/lib/atomy.rb ADDED
@@ -0,0 +1,37 @@
1
+ require "atomy/method"
2
+
3
+ class Object
4
+ attr_reader :atomy_methods
5
+
6
+ def atomy_methods
7
+ @atomy_methods ||= {}
8
+ end
9
+ end
10
+
11
+ module Atomy
12
+ module_function
13
+
14
+ def register_branch(target, name, branch)
15
+ methods = target.atomy_methods
16
+ method = methods[name] ||= Atomy::Method.new(name)
17
+ branch = method.add_branch(branch)
18
+ [method, branch]
19
+ end
20
+
21
+ def define_branch(binding, name, branch)
22
+ target =
23
+ if branch.receiver
24
+ branch.receiver.target
25
+ else
26
+ binding.constant_scope.for_method_definition
27
+ end
28
+
29
+ method, branch = register_branch(target, name, branch)
30
+
31
+ if branch.name
32
+ Rubinius.add_method(branch.name, branch.as_method, target, :public)
33
+ end
34
+
35
+ Rubinius.add_method(name, method.build, target, :public)
36
+ end
37
+ end
@@ -0,0 +1,256 @@
1
+ require "atomy/grammar"
2
+ require "atomy/module"
3
+ require "atomy/code/assign"
4
+ require "atomy/code/block"
5
+ require "atomy/code/class_variable"
6
+ require "atomy/code/constant"
7
+ require "atomy/code/define_method"
8
+ require "atomy/code/define_function"
9
+ require "atomy/code/false"
10
+ require "atomy/code/instance_variable"
11
+ require "atomy/code/integer"
12
+ require "atomy/code/list"
13
+ require "atomy/code/nil"
14
+ require "atomy/code/pattern"
15
+ require "atomy/code/pattern/and"
16
+ require "atomy/code/pattern/quasi_quote"
17
+ require "atomy/code/pattern/splat"
18
+ require "atomy/code/pattern/wildcard"
19
+ require "atomy/code/quasi_quote"
20
+ require "atomy/code/quote"
21
+ require "atomy/code/self"
22
+ require "atomy/code/send"
23
+ require "atomy/code/sequence"
24
+ require "atomy/code/string_literal"
25
+ require "atomy/code/symbol"
26
+ require "atomy/code/true"
27
+ require "atomy/code/undefined"
28
+ require "atomy/code/variable"
29
+ require "atomy/node/meta"
30
+ require "atomy/node/equality"
31
+ require "atomy/pattern/and"
32
+ require "atomy/pattern/equality"
33
+ require "atomy/pattern/kind_of"
34
+ require "atomy/pattern/quasi_quote"
35
+ require "atomy/pattern/splat"
36
+ require "atomy/pattern/wildcard"
37
+ require "atomy/message_structure"
38
+
39
+ module Atomy
40
+ Bootstrap = Atomy::Module.new do
41
+ def expand(node)
42
+ node.accept(NodeExpander.new(self)) || super
43
+ end
44
+
45
+ def pattern(node)
46
+ node.accept(PatternExpander.new(self)) || super
47
+ end
48
+
49
+ def macro_definer(pattern, body)
50
+ BootstrapHelper::WithGrammar.new(Atomy::Code::DefineMethod.new(:expand, body, nil, [pattern]))
51
+ end
52
+
53
+ def pattern_definer(pattern, body)
54
+ BootstrapHelper::WithGrammar.new(Atomy::Code::DefineMethod.new(:pattern, body, nil, [pattern]))
55
+ end
56
+
57
+ def make_send(recv, msg, args = [])
58
+ Atomy::Code::Send.new(recv, msg.text, args)
59
+ end
60
+
61
+ def make_constant(name, parent = nil)
62
+ Atomy::Code::Constant.new(name, parent)
63
+ end
64
+
65
+ def make_sequence(nodes)
66
+ Atomy::Grammar::AST::Sequence.new(nodes)
67
+ end
68
+
69
+ def make_quasiquote(node)
70
+ Atomy::Grammar::AST::QuasiQuote.new(node)
71
+ end
72
+
73
+ private
74
+
75
+ class NodeExpander
76
+ def initialize(mod)
77
+ @module = mod
78
+ end
79
+
80
+ def visit(node)
81
+ structure = Atomy::MessageStructure.new(node)
82
+
83
+ block = nil
84
+ if block_arg = structure.block
85
+ block = Atomy::Code::Block.new(
86
+ Atomy::Code::Sequence.new(block_arg.body),
87
+ block_arg.arguments,
88
+ nil,
89
+ false,
90
+ )
91
+ end
92
+
93
+ Code::Send.new(
94
+ structure.receiver,
95
+ structure.name,
96
+ structure.arguments,
97
+ structure.splat_argument,
98
+ structure.proc_argument,
99
+ block,
100
+ )
101
+ rescue Atomy::MessageStructure::UnknownMessageStructure
102
+ end
103
+
104
+ def visit_stringliteral(node)
105
+ Code::StringLiteral.new(node.value)
106
+ end
107
+
108
+ def visit_sequence(node)
109
+ Code::Sequence.new(node.nodes)
110
+ end
111
+
112
+ def visit_list(node)
113
+ Code::List.new(node.nodes)
114
+ end
115
+
116
+ def visit_word(node)
117
+ case node.text
118
+ when :self
119
+ Code::Self.new
120
+ else
121
+ Code::Variable.new(node.text)
122
+ end
123
+ end
124
+
125
+ def visit_constant(node)
126
+ Code::Constant.new(node.text)
127
+ end
128
+
129
+ def visit_number(node)
130
+ Code::Integer.new(node.value)
131
+ end
132
+
133
+ def visit_quote(node)
134
+ Code::Quote.new(node.node)
135
+ end
136
+
137
+ def visit_quasiquote(node)
138
+ Code::QuasiQuote.new(node.node)
139
+ end
140
+ end
141
+
142
+ class PatternExpander
143
+ def initialize(mod)
144
+ @module = mod
145
+ end
146
+
147
+ def visit(_)
148
+ nil
149
+ end
150
+
151
+ def visit_word(node)
152
+ name = nil
153
+ if node.text != :_
154
+ name = node.text
155
+ end
156
+
157
+ Code::Pattern::Wildcard.new(name)
158
+ end
159
+
160
+ def visit_number(node)
161
+ Code::Pattern.new(
162
+ Code::Send.new(
163
+ Code::Constant.new(
164
+ :Equality,
165
+ Code::Constant.new(
166
+ :Pattern,
167
+ Code::Constant.new(:Atomy))),
168
+ :new,
169
+ [node]))
170
+ end
171
+
172
+ def visit_quote(node)
173
+ Code::Pattern.new(
174
+ Code::Send.new(
175
+ Code::Constant.new(
176
+ :Equality,
177
+ Code::Constant.new(
178
+ :Pattern,
179
+ Code::Constant.new(:Atomy))),
180
+ :new,
181
+ [node]))
182
+ end
183
+
184
+ def visit_quasiquote(node)
185
+ Code::Pattern::QuasiQuote.new(node, @module)
186
+ end
187
+
188
+ def visit_prefix(node)
189
+ if node.operator == :*
190
+ Code::Pattern::Splat.new(@module.pattern(node.node))
191
+ end
192
+ end
193
+
194
+ def visit_infix(node)
195
+ if node.operator == :&
196
+ Code::Pattern::And.new(@module.pattern(node.left), @module.pattern(node.right))
197
+ end
198
+ end
199
+
200
+ def visit_constant(node)
201
+ Code::Pattern.new(
202
+ Code::Send.new(
203
+ Code::Constant.new(
204
+ :KindOf,
205
+ Code::Constant.new(
206
+ :Pattern,
207
+ Code::Constant.new(:Atomy))),
208
+ :new,
209
+ [node]))
210
+ end
211
+ end
212
+ end
213
+
214
+ # helpers that shouldn't be exposed through using Bootstrap
215
+ module BootstrapHelper
216
+ extend self
217
+
218
+ class WithGrammar
219
+ def initialize(body)
220
+ @body = body
221
+ end
222
+
223
+ def bytecode(gen, mod)
224
+ gen.create_block(build_block(gen.state.scope, mod))
225
+ gen.send(:call, 0)
226
+ end
227
+
228
+ private
229
+
230
+ def build_block(scope, mod)
231
+ Atomy::Compiler.generate(mod.file) do |blk|
232
+ # close over the outer scope
233
+ blk.state.scope.parent = scope
234
+
235
+ # capture original module
236
+ blk.push_scope
237
+ blk.send(:module, 0)
238
+
239
+ # add Atomy::Grammar::AST to the constant scope
240
+ blk.push_cpath_top
241
+ blk.find_const(:Atomy)
242
+ blk.find_const(:Grammar)
243
+ blk.find_const(:AST)
244
+ blk.add_scope
245
+
246
+ # restore original module for definition targets
247
+ blk.push_scope
248
+ blk.swap
249
+ blk.send(:current_module=, 1)
250
+
251
+ mod.compile(blk, @body)
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end