rltk 3.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +21 -22
- data/lib/rltk/ast.rb +185 -118
- data/lib/rltk/cfg.rb +157 -103
- data/lib/rltk/cg/basic_block.rb +19 -19
- data/lib/rltk/cg/bindings.rb +16 -16
- data/lib/rltk/cg/builder.rb +129 -129
- data/lib/rltk/cg/context.rb +7 -7
- data/lib/rltk/cg/contractor.rb +7 -7
- data/lib/rltk/cg/execution_engine.rb +30 -30
- data/lib/rltk/cg/function.rb +37 -37
- data/lib/rltk/cg/generated_bindings.rb +3932 -3932
- data/lib/rltk/cg/generic_value.rb +17 -17
- data/lib/rltk/cg/instruction.rb +116 -116
- data/lib/rltk/cg/llvm.rb +22 -22
- data/lib/rltk/cg/memory_buffer.rb +7 -7
- data/lib/rltk/cg/module.rb +73 -73
- data/lib/rltk/cg/pass_manager.rb +35 -35
- data/lib/rltk/cg/target.rb +41 -41
- data/lib/rltk/cg/triple.rb +7 -7
- data/lib/rltk/cg/type.rb +75 -75
- data/lib/rltk/cg/value.rb +161 -161
- data/lib/rltk/lexer.rb +57 -57
- data/lib/rltk/lexers/calculator.rb +7 -7
- data/lib/rltk/lexers/ebnf.rb +5 -5
- data/lib/rltk/parser.rb +338 -295
- data/lib/rltk/parsers/infix_calc.rb +7 -7
- data/lib/rltk/parsers/postfix_calc.rb +3 -3
- data/lib/rltk/parsers/prefix_calc.rb +3 -3
- data/lib/rltk/token.rb +13 -13
- data/lib/rltk/version.rb +6 -6
- data/test/cg/tc_basic_block.rb +17 -17
- data/test/cg/tc_control_flow.rb +41 -41
- data/test/cg/tc_function.rb +4 -4
- data/test/cg/tc_generic_value.rb +3 -3
- data/test/cg/tc_instruction.rb +53 -53
- data/test/cg/tc_math.rb +12 -12
- data/test/cg/tc_module.rb +14 -14
- data/test/cg/tc_transforms.rb +11 -11
- data/test/cg/tc_type.rb +12 -12
- data/test/cg/tc_value.rb +35 -35
- data/test/cg/ts_cg.rb +5 -5
- data/test/tc_ast.rb +137 -60
- data/test/tc_cfg.rb +34 -34
- data/test/tc_lexer.rb +42 -42
- data/test/tc_parser.rb +250 -173
- data/test/tc_token.rb +2 -2
- data/test/ts_rltk.rb +8 -8
- metadata +84 -85
- data/lib/rltk/cg/old_generated_bindings.rb +0 -6152
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99843025256c5d1cdcd1b826714ccc48fc2ebd36
|
4
|
+
data.tar.gz: fd8b9750f1fa95c9a810a3395820c4c9e88c6e99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bfb8a1cad07ed24d3f26453a028878e4e18875ad1c417d55aa9c42f065f9b2bdcf5491139bf0355b0d6b4027317309823983dbd7ca164e00b8c3320980ea614
|
7
|
+
data.tar.gz: 6e55e4df8368b686d966aa6bcd2d5431b81b59d25327f41b20bd1df3c23c89e4fac12d8d4d4e6b0836ad7b2467170582a30fc2f5bdce30f2fda6d41b0c77c354
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# Author:
|
2
|
-
# Project:
|
3
|
-
# Date:
|
4
|
-
# Description:
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This is RLTK's Rakefile.
|
5
5
|
|
6
6
|
##############
|
7
7
|
# Rake Tasks #
|
@@ -91,7 +91,7 @@ end
|
|
91
91
|
request_file('yard', 'Yard is not installed.') do
|
92
92
|
YARD::Rake::YardocTask.new do |t|
|
93
93
|
yardlib = File.join(File.dirname(__FILE__), 'yardlib/rltk.rb')
|
94
|
-
|
94
|
+
|
95
95
|
t.options = [
|
96
96
|
'-e', yardlib,
|
97
97
|
'--title', 'The Ruby Language Toolkit',
|
@@ -99,7 +99,7 @@ request_file('yard', 'Yard is not installed.') do
|
|
99
99
|
'-M', 'redcarpet',
|
100
100
|
'--private'
|
101
101
|
]
|
102
|
-
|
102
|
+
|
103
103
|
t.files = Dir['lib/**/*.rb'] +
|
104
104
|
['-'] +
|
105
105
|
Dir['examples/kazoo/**/*.md'].sort
|
@@ -113,20 +113,20 @@ end
|
|
113
113
|
desc 'Generate the bindings for LLVM.'
|
114
114
|
task :gen_bindings do
|
115
115
|
require 'ffi_gen'
|
116
|
-
|
116
|
+
|
117
117
|
# Generate the standard LLVM bindings.
|
118
|
-
|
118
|
+
|
119
119
|
deprecated = [
|
120
120
|
# BitReader.h
|
121
121
|
'LLVMGetBitcodeModuleProviderInContext',
|
122
122
|
'LLVMGetBitcodeModuleProvider',
|
123
|
-
|
123
|
+
|
124
124
|
# BitWriter.h
|
125
125
|
'LLVMWriteBitcodeToFileHandle',
|
126
|
-
|
126
|
+
|
127
127
|
# Core.h
|
128
128
|
'LLVMCreateFunctionPassManager',
|
129
|
-
|
129
|
+
|
130
130
|
# ExectionEngine.h
|
131
131
|
'LLVMCreateExecutionEngine',
|
132
132
|
'LLVMCreateInterpreter',
|
@@ -134,10 +134,10 @@ task :gen_bindings do
|
|
134
134
|
'LLVMAddModuleProvider',
|
135
135
|
'LLVMRemoveModuleProvider'
|
136
136
|
]
|
137
|
-
|
137
|
+
|
138
138
|
headers = [
|
139
139
|
'llvm-c/Core.h',
|
140
|
-
|
140
|
+
|
141
141
|
'llvm-c/Analysis.h',
|
142
142
|
'llvm-c/BitReader.h',
|
143
143
|
'llvm-c/BitWriter.h',
|
@@ -151,13 +151,13 @@ task :gen_bindings do
|
|
151
151
|
'llvm-c/Support.h',
|
152
152
|
'llvm-c/Target.h',
|
153
153
|
'llvm-c/TargetMachine.h',
|
154
|
-
|
154
|
+
|
155
155
|
'llvm-c/Transforms/IPO.h',
|
156
156
|
'llvm-c/Transforms/PassManagerBuilder.h',
|
157
157
|
'llvm-c/Transforms/Scalar.h',
|
158
158
|
'llvm-c/Transforms/Vectorize.h'
|
159
159
|
]
|
160
|
-
|
160
|
+
|
161
161
|
FFIGen.generate(
|
162
162
|
module_name: 'RLTK::CG::Bindings',
|
163
163
|
ffi_lib: "LLVM-#{RLTK::LLVM_TARGET_VERSION}",
|
@@ -171,28 +171,27 @@ end
|
|
171
171
|
|
172
172
|
desc 'Find LLVM bindings with a regular expression.'
|
173
173
|
task :find_bind, :part do |t, args|
|
174
|
-
|
174
|
+
|
175
175
|
# Get the task argument.
|
176
176
|
part = Regexp.new(args[:part])
|
177
|
-
|
177
|
+
|
178
178
|
# Require the Bindings module.
|
179
179
|
require 'rltk/cg/bindings'
|
180
|
-
|
180
|
+
|
181
181
|
syms =
|
182
182
|
Symbol.all_symbols.select do |sym|
|
183
183
|
sym = sym.to_s.downcase
|
184
|
-
|
184
|
+
|
185
185
|
sym[0..3] == 'llvm' and sym[4..-1] =~ part
|
186
186
|
end.sort
|
187
|
-
|
187
|
+
|
188
188
|
puts
|
189
189
|
if not syms.empty?
|
190
190
|
puts "Matching bindings [#{syms.length}]:"
|
191
191
|
syms.each { |sym| puts "\t#{sym}" }
|
192
|
-
|
192
|
+
|
193
193
|
else
|
194
194
|
puts 'No matching bindings.'
|
195
195
|
end
|
196
196
|
puts
|
197
197
|
end
|
198
|
-
|
data/lib/rltk/ast.rb
CHANGED
@@ -12,6 +12,7 @@ require 'filigree/abstract_class'
|
|
12
12
|
require 'filigree/class'
|
13
13
|
require 'filigree/match'
|
14
14
|
require 'filigree/types'
|
15
|
+
require 'filigree/visitor'
|
15
16
|
|
16
17
|
#######################
|
17
18
|
# Classes and Modules #
|
@@ -20,22 +21,29 @@ require 'filigree/types'
|
|
20
21
|
module RLTK
|
21
22
|
# This class is a good start for all your abstract syntax tree node needs.
|
22
23
|
class ASTNode
|
23
|
-
|
24
|
+
|
25
|
+
include Filigree::Visitable
|
26
|
+
|
24
27
|
extend Filigree::AbstractClass
|
25
28
|
extend Filigree::Destructurable
|
26
|
-
|
29
|
+
|
27
30
|
# @return [ASTNode] Reference to the parent node.
|
28
31
|
attr_accessor :parent
|
29
|
-
|
32
|
+
|
30
33
|
# @return [Hash] The notes hash for this node.
|
31
34
|
attr_reader :notes
|
32
|
-
|
35
|
+
|
33
36
|
#################
|
34
37
|
# Class Methods #
|
35
38
|
#################
|
36
|
-
|
39
|
+
|
37
40
|
class << self
|
38
|
-
|
41
|
+
|
42
|
+
# @return [Array<Symbol>] List of members (children and values) that have array types
|
43
|
+
def array_members
|
44
|
+
@array_members
|
45
|
+
end
|
46
|
+
|
39
47
|
# Check to make sure a name isn't re-defining a value or child.
|
40
48
|
#
|
41
49
|
# @raise [ArgumentError] Raised if the name is already used for an existing value or child
|
@@ -43,30 +51,38 @@ module RLTK
|
|
43
51
|
if @child_names.include? name
|
44
52
|
raise ArgumentError, "Class #{self} or one of its superclasses already defines a child named #{name}"
|
45
53
|
end
|
46
|
-
|
54
|
+
|
47
55
|
if @value_names.include?(name)
|
48
56
|
raise ArgumentError, "Class #{self} or one of its superclasses already defines a value named #{name}"
|
49
57
|
end
|
50
58
|
end
|
51
|
-
|
52
|
-
# Installs instance class
|
59
|
+
|
60
|
+
# Installs instance class variables into a class.
|
53
61
|
#
|
54
62
|
# @return [void]
|
55
63
|
def install_icvars
|
56
64
|
if self.superclass == ASTNode
|
57
|
-
@child_names
|
58
|
-
@
|
59
|
-
@
|
60
|
-
|
65
|
+
@child_names = Array.new
|
66
|
+
@value_names = Array.new
|
67
|
+
@array_members = Array.new
|
68
|
+
|
69
|
+
@member_order = :values
|
70
|
+
@def_order = Array.new
|
71
|
+
@inc_children = Array.new
|
72
|
+
@inc_values = Array.new
|
61
73
|
else
|
62
|
-
@child_names
|
63
|
-
@
|
64
|
-
@
|
65
|
-
|
74
|
+
@child_names = self.superclass.child_names.clone
|
75
|
+
@value_names = self.superclass.value_names.clone
|
76
|
+
@array_members = self.superclass.array_members.clone
|
77
|
+
|
78
|
+
@member_order = (v = self.superclass.member_order).is_a?(Symbol) ? v : v.clone
|
79
|
+
@def_order = self.superclass.def_order.clone
|
80
|
+
@inc_children = self.superclass.inc_children.clone
|
81
|
+
@inc_values = self.superclass.inc_values.clone
|
66
82
|
end
|
67
83
|
end
|
68
84
|
protected :install_icvars
|
69
|
-
|
85
|
+
|
70
86
|
# Called when the Lexer class is sub-classed, it installes
|
71
87
|
# necessary instance class variables.
|
72
88
|
#
|
@@ -76,50 +92,56 @@ module RLTK
|
|
76
92
|
def inherited(klass)
|
77
93
|
klass.install_icvars
|
78
94
|
end
|
79
|
-
|
95
|
+
|
80
96
|
# Defined a child for this AST class and its subclasses.
|
81
97
|
# The name of the child will be used to define accessor
|
82
98
|
# methods that include type checking. The type of this
|
83
99
|
# child must be a subclass of the ASTNode class.
|
84
100
|
#
|
85
|
-
# @param [String, Symbol] name Name of child node
|
101
|
+
# @param [String, Symbol] name Name of child node
|
86
102
|
# @param [Class] type Type of child node. Must be a subclass of ASTNode.
|
103
|
+
# @param [Boolean] omit Include the child in the constructor or not
|
87
104
|
#
|
88
105
|
# @return [void]
|
89
|
-
def child(name, type)
|
106
|
+
def child(name, type, omit = false)
|
90
107
|
check_odr(name)
|
91
|
-
|
108
|
+
|
92
109
|
if type.is_a?(Array) and type.length == 1
|
93
110
|
t = type.first
|
94
|
-
|
111
|
+
|
95
112
|
elsif type.is_a?(Class)
|
96
113
|
t = type
|
97
|
-
|
114
|
+
|
98
115
|
else
|
99
116
|
raise 'Child and Value types must be a class name or an array with a single class name element.'
|
100
117
|
end
|
101
|
-
|
102
|
-
# Check to make sure that type is a subclass of
|
103
|
-
# ASTNode.
|
118
|
+
|
119
|
+
# Check to make sure that type is a subclass of ASTNode.
|
104
120
|
if not t.subclass_of?(ASTNode)
|
105
121
|
raise "A child's type specification must be a subclass of ASTNode."
|
106
122
|
end
|
107
|
-
|
108
|
-
@child_names
|
109
|
-
@
|
123
|
+
|
124
|
+
@child_names << name
|
125
|
+
@array_members << name if type.is_a?(Array)
|
126
|
+
|
127
|
+
if not omit
|
128
|
+
@def_order << name
|
129
|
+
@inc_children << name
|
130
|
+
end
|
131
|
+
|
110
132
|
define_accessor(name, type, true)
|
111
133
|
end
|
112
|
-
|
134
|
+
|
113
135
|
# @return [Array<Symbol>] Array of the names of this node class's children
|
114
136
|
def child_names
|
115
137
|
@child_names
|
116
138
|
end
|
117
|
-
|
118
|
-
# @return [Array] Array of
|
119
|
-
def
|
120
|
-
@
|
139
|
+
|
140
|
+
# @return [Array<Symbol>] Array of names of values/children in the order they were defined
|
141
|
+
def def_order
|
142
|
+
@def_order
|
121
143
|
end
|
122
|
-
|
144
|
+
|
123
145
|
# This method defines a type checking accessor named *name*
|
124
146
|
# with type *type*.
|
125
147
|
#
|
@@ -130,31 +152,31 @@ module RLTK
|
|
130
152
|
# @return [void]
|
131
153
|
def define_accessor(name, type, set_parent = false)
|
132
154
|
ivar_name = ('@' + name.to_s).to_sym
|
133
|
-
|
155
|
+
|
134
156
|
define_method(name) do
|
135
157
|
self.instance_variable_get(ivar_name)
|
136
158
|
end
|
137
|
-
|
159
|
+
|
138
160
|
if type.is_a?(Class)
|
139
161
|
if set_parent
|
140
162
|
define_method((name.to_s + '=').to_sym) do |value|
|
141
163
|
self.instance_variable_set(ivar_name, check_type(value, type, nil, true))
|
142
164
|
value.parent = self if value
|
143
165
|
end
|
144
|
-
|
166
|
+
|
145
167
|
else
|
146
168
|
define_method((name.to_s + '=').to_sym) do |value|
|
147
169
|
self.instance_variable_set(ivar_name, check_type(value, type, nil, true))
|
148
170
|
end
|
149
171
|
end
|
150
|
-
|
172
|
+
|
151
173
|
else
|
152
174
|
if set_parent
|
153
175
|
define_method((name.to_s + '=').to_sym) do |value|
|
154
176
|
self.instance_variable_set(ivar_name, check_array_type(value, type.first, nil, true))
|
155
177
|
value.each { |c| c.parent = self }
|
156
178
|
end
|
157
|
-
|
179
|
+
|
158
180
|
else
|
159
181
|
define_method((name.to_s + '=').to_sym) do |value|
|
160
182
|
self.instance_variable_set(ivar_name, check_array_type(value, type.first, nil, true))
|
@@ -163,48 +185,87 @@ module RLTK
|
|
163
185
|
end
|
164
186
|
end
|
165
187
|
private :define_accessor
|
166
|
-
|
188
|
+
|
189
|
+
# Define a custom ordering for the class to use when building the
|
190
|
+
# default constructor and destructurer.
|
191
|
+
#
|
192
|
+
# @param [Array<Symbol>] members List of member names
|
193
|
+
#
|
194
|
+
# @return [void]
|
195
|
+
def custom_order(*members)
|
196
|
+
@member_order = members
|
197
|
+
end
|
198
|
+
|
199
|
+
# @return [Array<Symbol>] Array of the names of children that should be included in the constructor
|
200
|
+
def inc_children
|
201
|
+
@inc_children
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return [Array<Symbol>] Array of the names of values that should be included in the constructor
|
205
|
+
def inc_values
|
206
|
+
@inc_values
|
207
|
+
end
|
208
|
+
|
209
|
+
# A getter and setter for a class's initialization order. If the
|
210
|
+
# order value is `:values` the constructor will expect all of the
|
211
|
+
# values and then the children. If it is `:children` then the
|
212
|
+
# constructor expects children and then values. If it is `:def`
|
213
|
+
# the constructor expects to values and children in the order that
|
214
|
+
# they were defined. If val is nil the current value will be
|
215
|
+
# returned.
|
216
|
+
#
|
217
|
+
# The default ordering is `:values`, which matches the behavior of
|
218
|
+
# previous versions of RLTK.
|
219
|
+
#
|
220
|
+
# @param [:values, :children, :def] val The new initialization order
|
221
|
+
#
|
222
|
+
# @return [:values, :children, :def] The current initialization order
|
223
|
+
def member_order(val = nil)
|
224
|
+
if val
|
225
|
+
@member_order = val
|
226
|
+
else
|
227
|
+
@member_order
|
228
|
+
end
|
229
|
+
end
|
230
|
+
alias :order :member_order
|
231
|
+
|
167
232
|
# Defined a value for this AST class and its subclasses.
|
168
233
|
# The name of the value will be used to define accessor
|
169
234
|
# methods that include type checking.
|
170
235
|
#
|
171
236
|
# @param [String, Symbol] name Name of value
|
172
237
|
# @param [Class] type Type of value
|
238
|
+
# @param [Boolean] omit Include the value in the constructor or not
|
173
239
|
#
|
174
240
|
# @return [void]
|
175
|
-
def value(name, type)
|
241
|
+
def value(name, type, omit = false)
|
176
242
|
check_odr(name)
|
177
|
-
|
178
|
-
if type.is_a?(Array) and type.length == 1
|
179
|
-
t = type.first
|
180
|
-
|
181
|
-
elsif type.is_a?(Class)
|
182
|
-
t = type
|
183
|
-
|
184
|
-
else
|
243
|
+
|
244
|
+
if not (type.is_a?(Class) or (type.is_a?(Array) and type.length == 1))
|
185
245
|
raise 'Child and Value types must be a class name or an array with a single class name element.'
|
186
246
|
end
|
187
|
-
|
188
|
-
@value_names
|
189
|
-
@
|
247
|
+
|
248
|
+
@value_names << name
|
249
|
+
@array_members << name if type.is_a?(Array)
|
250
|
+
|
251
|
+
if not omit
|
252
|
+
@def_order << name
|
253
|
+
@inc_values << name
|
254
|
+
end
|
255
|
+
|
190
256
|
define_accessor(name, type)
|
191
257
|
end
|
192
|
-
|
258
|
+
|
193
259
|
# @return [Array<Symbol>] Array of the names of this node class's values
|
194
260
|
def value_names
|
195
261
|
@value_names
|
196
262
|
end
|
197
|
-
|
198
|
-
# @return [Array<Symbol>] Array of the types of this node class's values
|
199
|
-
def value_types
|
200
|
-
@value_types
|
201
|
-
end
|
202
263
|
end
|
203
|
-
|
264
|
+
|
204
265
|
####################
|
205
266
|
# Instance Methods #
|
206
267
|
####################
|
207
|
-
|
268
|
+
|
208
269
|
# Used for AST comparison, this function will return true if the two
|
209
270
|
# nodes are of the same class and all of their values and children
|
210
271
|
# are equal.
|
@@ -215,41 +276,42 @@ module RLTK
|
|
215
276
|
def ==(other)
|
216
277
|
self.class == other.class and self.values == other.values and self.children == other.children
|
217
278
|
end
|
218
|
-
|
279
|
+
|
219
280
|
# @return [Object] Note with the name *key*
|
220
281
|
def [](key)
|
221
282
|
@notes[key]
|
222
283
|
end
|
223
|
-
|
284
|
+
|
224
285
|
# Sets the note named *key* to *value*.
|
225
286
|
def []=(key, value)
|
226
287
|
@notes[key] = value
|
227
288
|
end
|
228
|
-
|
289
|
+
|
229
290
|
# This method allows ASTNodes to be destructured for pattern matching.
|
230
|
-
def
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
291
|
+
def destructure(arity)
|
292
|
+
case self.class.member_order
|
293
|
+
when :values then (self.class.inc_values + self.class.inc_children)
|
294
|
+
when :children then (self.class.inc_children + self.class.inc_values)
|
295
|
+
when :def then self.class.def_order
|
296
|
+
when Array then self.class.member_order
|
297
|
+
end.map { |m| self.send m }
|
236
298
|
end
|
237
|
-
|
299
|
+
|
238
300
|
# @param [Class] as The type that should be returned by the method. Must be either Array or hash.
|
239
301
|
#
|
240
302
|
# @return [Array<ASTNode>, Hash{Symbol => ASTNode}] Array or Hash of this node's children.
|
241
303
|
def children(as = Array)
|
242
304
|
if as == Array
|
243
305
|
self.class.child_names.map { |name| self.send(name) }
|
244
|
-
|
306
|
+
|
245
307
|
elsif as == Hash
|
246
308
|
self.class.child_names.inject(Hash.new) { |h, name| h[name] = self.send(name); h }
|
247
|
-
|
309
|
+
|
248
310
|
else
|
249
311
|
raise 'Children can only be returned as an Array or a Hash.'
|
250
312
|
end
|
251
313
|
end
|
252
|
-
|
314
|
+
|
253
315
|
# Assigns an array or hash of AST nodes as the children of this node.
|
254
316
|
# If a hash is provided as an argument the key is used as the name of
|
255
317
|
# the child a object should be assigned to.
|
@@ -263,11 +325,11 @@ module RLTK
|
|
263
325
|
if children.length != self.class.child_names.length
|
264
326
|
raise 'Wrong number of children specified.'
|
265
327
|
end
|
266
|
-
|
328
|
+
|
267
329
|
self.class.child_names.each_with_index do |name, i|
|
268
330
|
self.send((name.to_s + '=').to_sym, children[i])
|
269
331
|
end
|
270
|
-
|
332
|
+
|
271
333
|
when Hash
|
272
334
|
children.each do |name, val|
|
273
335
|
if self.class.child_names.include?(name)
|
@@ -278,14 +340,14 @@ module RLTK
|
|
278
340
|
end
|
279
341
|
end
|
280
342
|
end
|
281
|
-
|
343
|
+
|
282
344
|
# Produce an exact copy of this tree.
|
283
345
|
#
|
284
346
|
# @return [ASTNode] A copy of the tree.
|
285
347
|
def copy
|
286
348
|
self.map { |c| c }
|
287
349
|
end
|
288
|
-
|
350
|
+
|
289
351
|
# Removes the note *key* from this node. If the *recursive* argument
|
290
352
|
# is true it will also remove the note from the node's children.
|
291
353
|
#
|
@@ -295,7 +357,7 @@ module RLTK
|
|
295
357
|
if recursive
|
296
358
|
self.children.each do |child|
|
297
359
|
next if not child
|
298
|
-
|
360
|
+
|
299
361
|
if child.is_a?(Array)
|
300
362
|
child.each { |c| c.delete_note(key, true) }
|
301
363
|
else
|
@@ -303,10 +365,10 @@ module RLTK
|
|
303
365
|
end
|
304
366
|
end
|
305
367
|
end
|
306
|
-
|
368
|
+
|
307
369
|
@notes.delete(key)
|
308
370
|
end
|
309
|
-
|
371
|
+
|
310
372
|
# This method is a simple wrapper around Marshal.dump, and is used
|
311
373
|
# to serialize an AST. You can use Marshal.load to reconstruct a
|
312
374
|
# serialized AST.
|
@@ -324,7 +386,7 @@ module RLTK
|
|
324
386
|
else raise TypeError, "AST#dump expects nil, a String, or an IO object for the dest parameter."
|
325
387
|
end
|
326
388
|
end
|
327
|
-
|
389
|
+
|
328
390
|
# An iterator over the node's children. The AST may be traversed in
|
329
391
|
# the following orders:
|
330
392
|
#
|
@@ -339,31 +401,31 @@ module RLTK
|
|
339
401
|
case order
|
340
402
|
when :pre
|
341
403
|
yield self
|
342
|
-
|
404
|
+
|
343
405
|
self.children.flatten.compact.each { |c| c.each(:pre, &block) }
|
344
|
-
|
406
|
+
|
345
407
|
when :post
|
346
408
|
self.children.flatten.compact.each { |c| c.each(:post, &block) }
|
347
|
-
|
409
|
+
|
348
410
|
yield self
|
349
|
-
|
411
|
+
|
350
412
|
when :level
|
351
413
|
level_queue = [self]
|
352
|
-
|
414
|
+
|
353
415
|
while node = level_queue.shift
|
354
416
|
yield node
|
355
|
-
|
417
|
+
|
356
418
|
level_queue += node.children.flatten.compact
|
357
419
|
end
|
358
420
|
end
|
359
421
|
end
|
360
|
-
|
422
|
+
|
361
423
|
# Tests to see if a note named *key* is present at this node.
|
362
424
|
def has_note?(key)
|
363
425
|
@notes.has_key?(key)
|
364
426
|
end
|
365
427
|
alias :'note?' :'has_note?'
|
366
|
-
|
428
|
+
|
367
429
|
# Instantiates a new ASTNode object. The arguments to this method are
|
368
430
|
# split into two lists: the set of values for this node and a list of
|
369
431
|
# its children. If the node has 2 values and 3 children you would
|
@@ -383,22 +445,27 @@ module RLTK
|
|
383
445
|
def initialize(*objects, &block)
|
384
446
|
@notes = Hash.new()
|
385
447
|
@parent = nil
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
448
|
+
|
449
|
+
pairs =
|
450
|
+
case self.class.member_order
|
451
|
+
when :values then (self.class.inc_values + self.class.inc_children)
|
452
|
+
when :children then (self.class.inc_children + self.class.inc_values)
|
453
|
+
when :def then self.class.def_order
|
454
|
+
when Array then self.class.member_order
|
455
|
+
end.zip(objects).first(objects.length)
|
456
|
+
|
457
|
+
pairs.each do |name, value|
|
458
|
+
self.send("#{name}=", value)
|
459
|
+
end
|
460
|
+
|
461
|
+
self.class.array_members.each do |member|
|
462
|
+
ivar_name = '@' + member.to_s
|
463
|
+
self.instance_variable_set(ivar_name, []) if self.instance_variable_get(ivar_name).nil?
|
464
|
+
end
|
465
|
+
|
399
466
|
self.instance_exec(&block) if not block.nil?
|
400
467
|
end
|
401
|
-
|
468
|
+
|
402
469
|
# Create a new tree by using the provided Proc object to map the
|
403
470
|
# nodes of this tree to new nodes. This is always done in
|
404
471
|
# post-order, meaning that all children of a node are visited before
|
@@ -409,7 +476,7 @@ module RLTK
|
|
409
476
|
# @return [Object] Result of calling the given block on the root node
|
410
477
|
def map(&block)
|
411
478
|
new_values = self.values.map { |v| v.clone }
|
412
|
-
|
479
|
+
|
413
480
|
new_children =
|
414
481
|
self.children.map do |c0|
|
415
482
|
case c0
|
@@ -418,13 +485,13 @@ module RLTK
|
|
418
485
|
when NilClass then nil
|
419
486
|
end
|
420
487
|
end
|
421
|
-
|
488
|
+
|
422
489
|
new_node = self.class.new(*new_values, *new_children)
|
423
490
|
new_node.notes = self.notes
|
424
|
-
|
491
|
+
|
425
492
|
block.call(new_node)
|
426
493
|
end
|
427
|
-
|
494
|
+
|
428
495
|
# Map the nodes in an AST to new nodes using the provided Proc
|
429
496
|
# object. This is always done in post-order, meaning that all
|
430
497
|
# children of a node are visited before the node itself.
|
@@ -443,10 +510,10 @@ module RLTK
|
|
443
510
|
when NilClass then nil
|
444
511
|
end
|
445
512
|
end
|
446
|
-
|
513
|
+
|
447
514
|
block.call(self)
|
448
515
|
end
|
449
|
-
|
516
|
+
|
450
517
|
# Set the notes for this node from a given hash.
|
451
518
|
#
|
452
519
|
# @param [Hash] new_notes The new notes for this node.
|
@@ -455,27 +522,27 @@ module RLTK
|
|
455
522
|
def notes=(new_notes)
|
456
523
|
@notes = new_notes.clone
|
457
524
|
end
|
458
|
-
|
525
|
+
|
459
526
|
# @return [ASTNode] Root of the abstract syntax tree.
|
460
527
|
def root
|
461
528
|
if @parent then @parent.root else self end
|
462
529
|
end
|
463
|
-
|
530
|
+
|
464
531
|
# @param [Class] as The type that should be returned by the method. Must be either Array or hash.
|
465
532
|
#
|
466
533
|
# @return [Array<Object>, Hash{Symbol => Object}] Array or Hash of this node's values.
|
467
534
|
def values(as = Array)
|
468
535
|
if as == Array
|
469
536
|
self.class.value_names.map { |name| self.send(name) }
|
470
|
-
|
537
|
+
|
471
538
|
elsif as == Hash
|
472
539
|
self.class.value_names.inject(Hash.new) { |h, name| h[name] = self.send(name); h }
|
473
|
-
|
540
|
+
|
474
541
|
else
|
475
542
|
raise 'Values can only be returned as an Array or a Hash.'
|
476
543
|
end
|
477
544
|
end
|
478
|
-
|
545
|
+
|
479
546
|
# Assigns an array or hash of objects as the values of this node. If
|
480
547
|
# a hash is provided as an argument the key is used as the name of
|
481
548
|
# the value an object should be assigned to.
|
@@ -487,11 +554,11 @@ module RLTK
|
|
487
554
|
if values.length != self.class.value_names.length
|
488
555
|
raise 'Wrong number of values specified.'
|
489
556
|
end
|
490
|
-
|
557
|
+
|
491
558
|
self.class.value_names.each_with_index do |name, i|
|
492
559
|
self.send((name.to_s + '=').to_sym, values[i])
|
493
560
|
end
|
494
|
-
|
561
|
+
|
495
562
|
when Hash
|
496
563
|
values.each do |name, val|
|
497
564
|
if self.class.value_names.include?(name)
|