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
@@ -0,0 +1,144 @@
1
+ require "atomy/compiler"
2
+ require "atomy/locals"
3
+ require "atomy/errors"
4
+
5
+ require "atomy/method"
6
+
7
+ module Atomy
8
+ class Module < ::Module
9
+ # [Symbol] Absolute path to the file the module was loaded from.
10
+ attr_reader :file
11
+
12
+ def file=(file)
13
+ @file = file
14
+ Rubinius::Type.set_module_name(self, File.basename(file.to_s).to_sym, Object)
15
+ end
16
+
17
+ # [Module] Modules users of this module should automatically use.
18
+ attr_reader :exported_modules
19
+
20
+ def initialize
21
+ extend self
22
+
23
+ @exported_modules = []
24
+
25
+ # easy accessor for the current module via ConstantScope lookup
26
+ const_set(:Self, self)
27
+
28
+ super
29
+ end
30
+
31
+ def export(*modules)
32
+ @exported_modules.concat(modules)
33
+ end
34
+
35
+ def compile(gen, node)
36
+ gen.set_line(node.line) if node.respond_to?(:line) && node.line
37
+
38
+ expanded = node
39
+ while expanded.is_a?(Atomy::Grammar::AST::Node)
40
+ expanded = expand(expanded)
41
+ end
42
+
43
+ expanded.bytecode(gen, self)
44
+ rescue
45
+ puts "when compiling: #{node}"
46
+ raise
47
+ end
48
+
49
+ def evaluate(node, binding = nil)
50
+ binding ||=
51
+ Binding.setup(
52
+ Rubinius::VariableScope.of_sender,
53
+ Rubinius::CompiledCode.of_sender,
54
+ Rubinius::ConstantScope.of_sender,
55
+ self)
56
+
57
+ code = Atomy::Compiler.compile(
58
+ node,
59
+ self,
60
+ Atomy::EvalLocalState.new(binding.variables))
61
+
62
+ code.add_metadata :for_eval, true
63
+
64
+ block = Atomy::Compiler.construct_block(code, binding)
65
+ block.call
66
+ end
67
+
68
+ def require(path)
69
+ Atomy::CodeLoader.require(path)
70
+ end
71
+
72
+ def inspect
73
+ if @file
74
+ super.sub(/>$/, " #{@file}>")
75
+ else
76
+ super
77
+ end
78
+ end
79
+
80
+ def use(mod)
81
+ extend mod
82
+ include mod
83
+
84
+ if mod.is_a?(self.class)
85
+ mod.exported_modules.each do |m|
86
+ use(m)
87
+ end
88
+ end
89
+
90
+ mod
91
+ end
92
+
93
+ # Node -> (Node | Code)
94
+ def expand(node)
95
+ raise UnknownCode.new(node)
96
+ end
97
+
98
+ # Node -> Code::Pattern
99
+ def pattern(node)
100
+ raise UnknownPattern.new(node)
101
+ end
102
+
103
+ def compile_context
104
+ return @compile_context if @compile_context
105
+
106
+ scope = Rubinius::ConstantScope.new(
107
+ self,
108
+ Rubinius::ConstantScope.new(Object))
109
+
110
+ meth = proc {}.block.compiled_code
111
+ meth.metadata = nil
112
+ meth.name = :__script__
113
+ meth.scope = scope
114
+
115
+ variables =
116
+ Rubinius::VariableScope.synthesize(
117
+ meth, self, nil, self, nil, Rubinius::Tuple.new(0))
118
+
119
+ if @file
120
+ script = meth.create_script
121
+ script.file_path = @file.to_s
122
+ script.data_path = File.expand_path(@file.to_s)
123
+ script.make_main!
124
+
125
+ scope.script = script
126
+ end
127
+
128
+ @compile_context = Binding.setup(variables, meth, scope)
129
+ end
130
+
131
+ private
132
+
133
+ # atomy module semantics are defined via 'extend self', but we have to
134
+ # make sure that later extends are added *after* self
135
+ #
136
+ # this ensures that modules a module use don't take priority over the
137
+ # module's own methods
138
+ def extend(mod)
139
+ return super if mod == self
140
+
141
+ mod.include_into(singleton_class.direct_superclass)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,169 @@
1
+ require "atomy/grammar"
2
+
3
+ module Atomy::Grammar::AST
4
+ class Node
5
+ def construct(gen)
6
+ raise "no #construct for #{self.class}"
7
+ end
8
+
9
+ private
10
+
11
+ def push_node(gen, name)
12
+ gen.push_cpath_top
13
+ gen.find_const(:Atomy)
14
+ gen.find_const(:Grammar)
15
+ gen.find_const(:AST)
16
+ gen.find_const(name)
17
+ end
18
+ end
19
+
20
+ class Sequence
21
+ def construct(gen)
22
+ push_node(gen, :Sequence)
23
+ @nodes.each do |node|
24
+ node.construct(gen)
25
+ end
26
+ gen.make_array(@nodes.size)
27
+ gen.send(:new, 1)
28
+ end
29
+ end
30
+
31
+ class Number
32
+ def construct(gen)
33
+ push_node(gen, :Number)
34
+ gen.push_int(@value)
35
+ gen.send(:new, 1)
36
+ end
37
+ end
38
+
39
+ class Literal
40
+ def construct(gen)
41
+ push_node(gen, :Literal)
42
+ gen.push_literal(@value)
43
+ gen.send(:new, 1)
44
+ end
45
+ end
46
+
47
+ class Quote
48
+ def construct(gen)
49
+ push_node(gen, :Quote)
50
+ @node.construct(gen)
51
+ gen.send(:new, 1)
52
+ end
53
+ end
54
+
55
+ class QuasiQuote
56
+ def construct(gen)
57
+ push_node(gen, :QuasiQuote)
58
+ @node.construct(gen)
59
+ gen.send(:new, 1)
60
+ end
61
+ end
62
+
63
+ class Unquote
64
+ def construct(gen)
65
+ push_node(gen, :Unquote)
66
+ @node.construct(gen)
67
+ gen.send(:new, 1)
68
+ end
69
+ end
70
+
71
+ class Constant
72
+ def construct(gen)
73
+ push_node(gen, :Constant)
74
+ gen.push_literal(@text)
75
+ gen.send(:new, 1)
76
+ end
77
+ end
78
+
79
+ class Word
80
+ def construct(gen)
81
+ push_node(gen, :Word)
82
+ gen.push_literal(@text)
83
+ gen.send(:new, 1)
84
+ end
85
+ end
86
+
87
+ class Prefix
88
+ def construct(gen)
89
+ push_node(gen, :Prefix)
90
+ @node.construct(gen)
91
+ gen.push_literal(@operator)
92
+ gen.send(:new, 2)
93
+ end
94
+ end
95
+
96
+ class Postfix
97
+ def construct(gen)
98
+ push_node(gen, :Postfix)
99
+ @node.construct(gen)
100
+ gen.push_literal(@operator)
101
+ gen.send(:new, 2)
102
+ end
103
+ end
104
+
105
+ class Infix
106
+ def construct(gen)
107
+ push_node(gen, :Infix)
108
+ if @left
109
+ @left.construct(gen)
110
+ else
111
+ gen.push_nil
112
+ end
113
+ @right.construct(gen)
114
+ gen.push_literal(@operator)
115
+ gen.send(:new, 3)
116
+ end
117
+ end
118
+
119
+ class Block
120
+ def construct(gen)
121
+ push_node(gen, :Block)
122
+ @nodes.each do |node|
123
+ node.construct(gen)
124
+ end
125
+ gen.make_array(@nodes.size)
126
+ gen.send(:new, 1)
127
+ end
128
+ end
129
+
130
+ class List
131
+ def construct(gen)
132
+ push_node(gen, :List)
133
+ @nodes.each do |node|
134
+ node.construct(gen)
135
+ end
136
+ gen.make_array(@nodes.size)
137
+ gen.send(:new, 1)
138
+ end
139
+ end
140
+
141
+ class Compose
142
+ def construct(gen)
143
+ push_node(gen, :Compose)
144
+ @left.construct(gen)
145
+ @right.construct(gen)
146
+ gen.send(:new, 2)
147
+ end
148
+ end
149
+
150
+ class Apply
151
+ def construct(gen)
152
+ push_node(gen, :Apply)
153
+ @node.construct(gen)
154
+ @arguments.each do |node|
155
+ node.construct(gen)
156
+ end
157
+ gen.make_array(@arguments.size)
158
+ gen.send(:new, 2)
159
+ end
160
+ end
161
+
162
+ class StringLiteral
163
+ def construct(gen)
164
+ push_node(gen, :StringLiteral)
165
+ gen.push_literal(@value)
166
+ gen.send(:new, 1)
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,113 @@
1
+ require "atomy/grammar"
2
+
3
+ module Atomy::Grammar::AST
4
+ class Node
5
+ end
6
+
7
+ class Sequence
8
+ def ==(other)
9
+ super || other.is_a?(self.class) && @nodes == other.nodes
10
+ end
11
+ end
12
+
13
+ class Number
14
+ def ==(other)
15
+ super || other.is_a?(self.class) && @value == other.value
16
+ end
17
+ end
18
+
19
+ class Literal
20
+ def ==(other)
21
+ super || other.is_a?(self.class) && @value == other.value
22
+ end
23
+ end
24
+
25
+ class Quote
26
+ def ==(other)
27
+ super || other.is_a?(self.class) && @node == other.node
28
+ end
29
+ end
30
+
31
+ class QuasiQuote
32
+ def ==(other)
33
+ super || other.is_a?(self.class) && @node == other.node
34
+ end
35
+ end
36
+
37
+ class Unquote
38
+ def ==(other)
39
+ super || other.is_a?(self.class) && @node == other.node
40
+ end
41
+ end
42
+
43
+ class Constant
44
+ def ==(other)
45
+ super || other.is_a?(self.class) && @text == other.text
46
+ end
47
+ end
48
+
49
+ class Word
50
+ def ==(other)
51
+ super || other.is_a?(self.class) && @text == other.text
52
+ end
53
+ end
54
+
55
+ class Prefix
56
+ def ==(other)
57
+ super || other.is_a?(self.class) && \
58
+ @operator == other.operator && \
59
+ @node == other.node
60
+ end
61
+ end
62
+
63
+ class Postfix
64
+ def ==(other)
65
+ super || other.is_a?(self.class) && \
66
+ @operator == other.operator && \
67
+ @node == other.node
68
+ end
69
+ end
70
+
71
+ class Infix
72
+ def ==(other)
73
+ super || other.is_a?(self.class) && \
74
+ @operator == other.operator && \
75
+ @left == other.left && \
76
+ @right == other.right
77
+ end
78
+ end
79
+
80
+ class Block
81
+ def ==(other)
82
+ super || other.is_a?(self.class) && @nodes == other.nodes
83
+ end
84
+ end
85
+
86
+ class List
87
+ def ==(other)
88
+ super || other.is_a?(self.class) && @nodes == other.nodes
89
+ end
90
+ end
91
+
92
+ class Compose
93
+ def ==(other)
94
+ super || other.is_a?(self.class) && \
95
+ @left == other.left && \
96
+ @right == other.right
97
+ end
98
+ end
99
+
100
+ class Apply
101
+ def ==(other)
102
+ super || other.is_a?(self.class) && \
103
+ @node == other.node && \
104
+ @arguments == other.arguments
105
+ end
106
+ end
107
+
108
+ class StringLiteral
109
+ def ==(other)
110
+ super || other.is_a?(self.class) && @value == other.value
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,206 @@
1
+ module Atomy::Grammar::AST
2
+ class Node
3
+ class << self
4
+ def basename
5
+ @basename ||= name.split("::").last.to_sym
6
+ end
7
+ end
8
+
9
+ def each_child
10
+ end
11
+
12
+ def each_attribute
13
+ end
14
+
15
+ def children
16
+ names = []
17
+
18
+ each_child do |name, _|
19
+ names << name
20
+ end
21
+
22
+ names
23
+ end
24
+
25
+ def attributes
26
+ names = []
27
+
28
+ each_attribute do |name, _|
29
+ names << name
30
+ end
31
+
32
+ names
33
+ end
34
+
35
+ def accept(x)
36
+ name = :"visit_#{self.class.basename.downcase}"
37
+
38
+ if x.respond_to?(name)
39
+ x.send(name, self)
40
+ else
41
+ x.visit(self)
42
+ end
43
+ end
44
+
45
+ # Recreate the node, calling the block for sub-nodes and using its return
46
+ # value in place of the node
47
+ def through
48
+ dup
49
+ end
50
+ end
51
+
52
+ class Sequence
53
+ def each_child
54
+ yield :nodes, @nodes
55
+ end
56
+
57
+ def through
58
+ self.class.new(nodes.collect { |n| yield n })
59
+ end
60
+ end
61
+
62
+ class Number
63
+ def each_attribute
64
+ yield :value, @value
65
+ end
66
+ end
67
+
68
+ class Literal
69
+ def each_attribute
70
+ yield :value, @value
71
+ end
72
+ end
73
+
74
+ class Quote
75
+ def each_child
76
+ yield :node, @node
77
+ end
78
+
79
+ def through
80
+ self.class.new(yield @node)
81
+ end
82
+ end
83
+
84
+ class QuasiQuote
85
+ def each_child
86
+ yield :node, @node
87
+ end
88
+
89
+ def through
90
+ self.class.new(yield @node)
91
+ end
92
+ end
93
+
94
+ class Unquote
95
+ def each_child
96
+ yield :node, @node
97
+ end
98
+
99
+ def through
100
+ self.class.new(yield @node)
101
+ end
102
+ end
103
+
104
+ class Constant
105
+ def each_attribute
106
+ yield :text, @text
107
+ end
108
+ end
109
+
110
+ class Word
111
+ def each_attribute
112
+ yield :text, @text
113
+ end
114
+ end
115
+
116
+ class Prefix
117
+ def each_attribute
118
+ yield :operator, @operator
119
+ end
120
+
121
+ def each_child
122
+ yield :node, @node
123
+ end
124
+
125
+ def through
126
+ self.class.new(yield(@node), @operator)
127
+ end
128
+ end
129
+
130
+ class Postfix
131
+ def each_attribute
132
+ yield :operator, @operator
133
+ end
134
+
135
+ def each_child
136
+ yield :node, @node
137
+ end
138
+
139
+ def through
140
+ self.class.new(yield(@node), @operator)
141
+ end
142
+ end
143
+
144
+ class Infix
145
+ def each_attribute
146
+ yield :operator, @operator
147
+ end
148
+
149
+ def each_child
150
+ yield :left, @left if @left
151
+ yield :right, @right
152
+ end
153
+
154
+ def through
155
+ self.class.new(@left && yield(@left), yield(@right), @operator)
156
+ end
157
+ end
158
+
159
+ class Block
160
+ def each_child
161
+ yield :nodes, @nodes
162
+ end
163
+
164
+ def through
165
+ self.class.new(@nodes.collect { |n| yield n })
166
+ end
167
+ end
168
+
169
+ class List
170
+ def each_child
171
+ yield :nodes, @nodes
172
+ end
173
+
174
+ def through
175
+ self.class.new(@nodes.collect { |n| yield n })
176
+ end
177
+ end
178
+
179
+ class Compose
180
+ def each_child
181
+ yield :left, @left
182
+ yield :right, @right
183
+ end
184
+
185
+ def through
186
+ self.class.new(yield(@left), yield(@right))
187
+ end
188
+ end
189
+
190
+ class Apply
191
+ def each_child
192
+ yield :node, @node
193
+ yield :arguments, @arguments
194
+ end
195
+
196
+ def through
197
+ self.class.new(yield(@node), @arguments.collect { |a| yield a })
198
+ end
199
+ end
200
+
201
+ class StringLiteral
202
+ def each_attribute
203
+ yield :value, @value
204
+ end
205
+ end
206
+ end