rltk 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +610 -0
- data/Rakefile +156 -21
- data/lib/rltk/ast.rb +179 -127
- data/lib/rltk/cfg.rb +131 -38
- data/lib/rltk/cg/basic_block.rb +167 -0
- data/lib/rltk/cg/bindings.rb +136 -0
- data/lib/rltk/cg/builder.rb +1095 -0
- data/lib/rltk/cg/context.rb +51 -0
- data/lib/rltk/cg/execution_engine.rb +172 -0
- data/lib/rltk/cg/function.rb +224 -0
- data/lib/rltk/cg/generated_bindings.rb +6158 -0
- data/lib/rltk/cg/generated_extended_bindings.rb +43 -0
- data/lib/rltk/cg/generic_value.rb +98 -0
- data/lib/rltk/cg/instruction.rb +498 -0
- data/lib/rltk/cg/llvm.rb +51 -0
- data/lib/rltk/cg/memory_buffer.rb +62 -0
- data/lib/rltk/cg/module.rb +328 -0
- data/lib/rltk/cg/pass_manager.rb +201 -0
- data/lib/rltk/cg/support.rb +29 -0
- data/lib/rltk/cg/type.rb +510 -0
- data/lib/rltk/cg/value.rb +1207 -0
- data/lib/rltk/cg.rb +33 -0
- data/lib/rltk/lexer.rb +135 -85
- data/lib/rltk/lexers/calculator.rb +4 -1
- data/lib/rltk/lexers/ebnf.rb +1 -4
- data/lib/rltk/parser.rb +360 -196
- data/lib/rltk/token.rb +29 -4
- data/lib/rltk/util/abstract_class.rb +25 -0
- data/lib/rltk/util/monkeys.rb +125 -0
- data/lib/rltk/version.rb +5 -2
- data/test/tc_ast.rb +11 -11
- data/test/tc_lexer.rb +41 -41
- data/test/tc_parser.rb +123 -97
- data/test/ts_rltk.rb +50 -0
- metadata +181 -87
- data/README +0 -390
data/Rakefile
CHANGED
@@ -7,35 +7,33 @@
|
|
7
7
|
# Rake Tasks #
|
8
8
|
##############
|
9
9
|
|
10
|
+
# Gems
|
10
11
|
require 'rake/testtask'
|
11
12
|
require 'bundler'
|
12
13
|
|
13
|
-
|
14
|
-
require 'rdoc/task'
|
15
|
-
|
16
|
-
RDoc::Task.new do |t|
|
17
|
-
t.title = 'The Ruby Language Toolkit'
|
18
|
-
t.main = 'README'
|
19
|
-
t.rdoc_dir = 'doc'
|
20
|
-
|
21
|
-
t.rdoc_files.include('README', 'lib/*.rb', 'lib/rltk/*.rb', 'lib/rltk/**/*.rb')
|
22
|
-
end
|
23
|
-
|
24
|
-
rescue LoadError
|
25
|
-
warn 'RDoc is not installed.'
|
26
|
-
end
|
14
|
+
require File.expand_path("../lib/rltk/version", __FILE__)
|
27
15
|
|
28
16
|
begin
|
29
|
-
require '
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
t.
|
17
|
+
require 'yard'
|
18
|
+
|
19
|
+
YARD::Rake::YardocTask.new do |t|
|
20
|
+
yardlib = File.join(File.dirname(__FILE__), 'yardlib/rltk.rb')
|
21
|
+
|
22
|
+
t.options = [
|
23
|
+
'-e', yardlib,
|
24
|
+
'--title', 'The Ruby Language Toolkit',
|
25
|
+
'-m', 'markdown',
|
26
|
+
'-M', 'redcarpet',
|
27
|
+
'-c', '.yardoc/cache',
|
28
|
+
'--private'
|
29
|
+
]
|
30
|
+
|
31
|
+
|
32
|
+
t.files = Dir['lib/**/*.rb'] + ['-'] + Dir['examples/kazoo/**/*.md'].sort
|
35
33
|
end
|
36
34
|
|
37
35
|
rescue LoadError
|
38
|
-
warn '
|
36
|
+
warn 'Yard is not installed. `gem install yard` to build documentation.'
|
39
37
|
end
|
40
38
|
|
41
39
|
Rake::TestTask.new do |t|
|
@@ -44,4 +42,141 @@ Rake::TestTask.new do |t|
|
|
44
42
|
t.test_files = FileList['test/ts_rltk.rb']
|
45
43
|
end
|
46
44
|
|
45
|
+
if RUBY_VERSION[0..2] == '1.8'
|
46
|
+
begin
|
47
|
+
require 'rcov/rcovtask'
|
48
|
+
|
49
|
+
Rcov::RcovTask.new do |t|
|
50
|
+
t.libs << 'test'
|
51
|
+
t.rcov_opts << '--exclude gems,ruby'
|
52
|
+
|
53
|
+
t.test_files = FileList['test/tc_*.rb']
|
54
|
+
end
|
55
|
+
|
56
|
+
rescue LoadError
|
57
|
+
warn 'Rcov not installed.'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Bundler tasks.
|
47
62
|
Bundler::GemHelper.install_tasks
|
63
|
+
|
64
|
+
# Rubygems Taks
|
65
|
+
begin
|
66
|
+
require 'rubygems/tasks'
|
67
|
+
|
68
|
+
Gem::Tasks.new do |t|
|
69
|
+
t.console.command = 'pry'
|
70
|
+
end
|
71
|
+
|
72
|
+
rescue LoadError
|
73
|
+
'rubygems-tasks not installed.'
|
74
|
+
end
|
75
|
+
|
76
|
+
desc 'Generate the bindings for LLVM.'
|
77
|
+
task :gen_bindings do
|
78
|
+
require 'ffi_gen'
|
79
|
+
|
80
|
+
# Generate the standard LLVM bindings.
|
81
|
+
|
82
|
+
blacklist = [
|
83
|
+
'LLVMGetMDNodeOperand',
|
84
|
+
'LLVMGetMDNodeNumOperands',
|
85
|
+
'LLVMInitializeAllTargetInfos',
|
86
|
+
'LLVMInitializeAllTargets',
|
87
|
+
'LLVMInitializeNativeTarget'
|
88
|
+
]
|
89
|
+
|
90
|
+
deprecated = [
|
91
|
+
# BitReader.h
|
92
|
+
'LLVMGetBitcodeModuleProviderInContext',
|
93
|
+
'LLVMGetBitcodeModuleProvider',
|
94
|
+
|
95
|
+
# BitWriter.h
|
96
|
+
'LLVMWriteBitcodeToFileHandle',
|
97
|
+
|
98
|
+
# Core.h
|
99
|
+
'LLVMCreateFunctionPassManager',
|
100
|
+
|
101
|
+
# ExectionEngine.h
|
102
|
+
'LLVMCreateExecutionEngine',
|
103
|
+
'LLVMCreateInterpreter',
|
104
|
+
'LLVMCreateJITCompiler',
|
105
|
+
'LLVMAddModuleProvider',
|
106
|
+
'LLVMRemoveModuleProvider'
|
107
|
+
]
|
108
|
+
|
109
|
+
headers = [
|
110
|
+
'llvm-c/Core.h',
|
111
|
+
|
112
|
+
'llvm-c/Analysis.h',
|
113
|
+
'llvm-c/BitReader.h',
|
114
|
+
'llvm-c/BitWriter.h',
|
115
|
+
'llvm-c/Disassembler.h',
|
116
|
+
'llvm-c/ExecutionEngine.h',
|
117
|
+
'llvm-c/Initialization.h',
|
118
|
+
'llvm-c/Object.h',
|
119
|
+
'llvm-c/Target.h',
|
120
|
+
|
121
|
+
'llvm-c/Transforms/IPO.h',
|
122
|
+
'llvm-c/Transforms/Scalar.h'
|
123
|
+
]
|
124
|
+
|
125
|
+
FFIGen.generate(
|
126
|
+
:module_name => 'RLTK::CG::Bindings',
|
127
|
+
:ffi_lib => "LLVM-#{RLTK::LLVM_TARGET_VERSION}",
|
128
|
+
:headers => headers,
|
129
|
+
:cflags => `llvm-config --cflags`.split,
|
130
|
+
:prefixes => ['LLVM'],
|
131
|
+
:blacklist => blacklist + deprecated,
|
132
|
+
:output => 'lib/rltk/cg/generated_bindings.rb'
|
133
|
+
)
|
134
|
+
|
135
|
+
# Generate the extended LLVM bindings.
|
136
|
+
|
137
|
+
headers = [
|
138
|
+
'llvm-ecb.h',
|
139
|
+
|
140
|
+
'llvm-ecb/support.h'
|
141
|
+
]
|
142
|
+
|
143
|
+
begin
|
144
|
+
FFIGen.generate(
|
145
|
+
:module_name => 'RLTK::CG::Bindings',
|
146
|
+
:ffi_lib => "LLVM-ECB-#{RLTK::LLVM_TARGET_VERSION}",
|
147
|
+
:headers => headers,
|
148
|
+
:cflags => `llvm-config --cflags`.split,
|
149
|
+
:prefixes => ['LLVM'],
|
150
|
+
:output => 'lib/rltk/cg/generated_extended_bindings.rb'
|
151
|
+
)
|
152
|
+
rescue
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
desc 'Find LLVM bindings with a regular expression.'
|
157
|
+
task :find_bind, :part do |t, args|
|
158
|
+
|
159
|
+
# Get the task argument.
|
160
|
+
part = Regexp.new(args[:part])
|
161
|
+
|
162
|
+
# Require the Bindings module.
|
163
|
+
require 'rltk/cg/bindings'
|
164
|
+
|
165
|
+
syms =
|
166
|
+
Symbol.all_symbols.select do |sym|
|
167
|
+
sym = sym.to_s.downcase
|
168
|
+
|
169
|
+
sym[0..3] == 'llvm' and sym[4..-1] =~ part
|
170
|
+
end.sort
|
171
|
+
|
172
|
+
puts
|
173
|
+
if not syms.empty?
|
174
|
+
puts "Matching bindings [#{syms.length}]:"
|
175
|
+
syms.each { |sym| puts "\t#{sym}" }
|
176
|
+
|
177
|
+
else
|
178
|
+
puts 'No matching bindings.'
|
179
|
+
end
|
180
|
+
puts
|
181
|
+
end
|
182
|
+
|
data/lib/rltk/ast.rb
CHANGED
@@ -3,45 +3,52 @@
|
|
3
3
|
# Date: 2011/01/19
|
4
4
|
# Description: This file provides a base Node class for ASTs.
|
5
5
|
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Ruby Language Toolkit
|
11
|
+
require 'rltk/util/monkeys'
|
12
|
+
|
13
|
+
#######################
|
14
|
+
# Classes and Modules #
|
15
|
+
#######################
|
16
|
+
|
6
17
|
module RLTK # :nodoc:
|
7
|
-
# A TypeMismatch is
|
18
|
+
# A TypeMismatch is raised when an object being set as a child or value of
|
8
19
|
# an ASTNode is of the wrong type.
|
9
|
-
class TypeMismatch <
|
20
|
+
class TypeMismatch < StandardError
|
10
21
|
|
11
|
-
# Instantiates a new TypeMismatch object.
|
12
|
-
#
|
13
|
-
#
|
22
|
+
# Instantiates a new TypeMismatch object.
|
23
|
+
#
|
24
|
+
# @param [Class] expected Expected type.
|
25
|
+
# @param [Klass] actual Actual type of object.
|
14
26
|
def initialize(expected, actual)
|
15
27
|
@expected = expected
|
16
28
|
@actual = actual
|
17
29
|
end
|
18
30
|
|
19
|
-
#
|
31
|
+
# @return [String] String representation of the error.
|
20
32
|
def to_s
|
21
33
|
"Type Mismatch: Expected #{@expected} but received #{@actual}."
|
22
34
|
end
|
23
35
|
end
|
24
36
|
|
25
|
-
# Returns true if klass0 is a subclass of klass1; false otherwise.
|
26
|
-
def self.subclass_of?(klass0, klass1)
|
27
|
-
begin
|
28
|
-
return true if klass0 == klass1
|
29
|
-
end while klass0 = klass0.superclass
|
30
|
-
|
31
|
-
return false
|
32
|
-
end
|
33
|
-
|
34
37
|
# This class is a good start for all your abstract syntax tree node needs.
|
35
38
|
class ASTNode
|
36
|
-
#
|
39
|
+
# @return [ASTNode] Reference to the parent node.
|
37
40
|
attr_accessor :parent
|
38
41
|
|
39
42
|
#################
|
40
43
|
# Class Methods #
|
41
44
|
#################
|
42
45
|
|
43
|
-
|
44
|
-
|
46
|
+
class << self
|
47
|
+
|
48
|
+
# Installs instance class varialbes into a class.
|
49
|
+
#
|
50
|
+
# @return [void]
|
51
|
+
def install_icvars
|
45
52
|
if self.superclass == ASTNode
|
46
53
|
@child_names = Array.new
|
47
54
|
@value_names = Array.new
|
@@ -49,126 +56,153 @@ module RLTK # :nodoc:
|
|
49
56
|
@child_names = self.superclass.child_names.clone
|
50
57
|
@value_names = self.superclass.value_names.clone
|
51
58
|
end
|
59
|
+
end
|
60
|
+
protected :install_icvars
|
61
|
+
|
62
|
+
# Called when the Lexer class is sub-classed, it installes
|
63
|
+
# necessary instance class variables.
|
64
|
+
#
|
65
|
+
# @param [Class] klass The class is inheriting from this class.
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
def inherited(klass)
|
69
|
+
klass.install_icvars
|
70
|
+
end
|
71
|
+
|
72
|
+
# Defined a child for this AST class and its subclasses.
|
73
|
+
# The name of the child will be used to define accessor
|
74
|
+
# methods that include type checking. The type of this
|
75
|
+
# child must be a subclass of the ASTNode class.
|
76
|
+
#
|
77
|
+
# @param [String, Symbol] name Name of child node.
|
78
|
+
# @param [Class] type Type of child node. Must be a subclass of ASTNode.
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
def child(name, type)
|
82
|
+
if type.is_a?(Array) and type.length == 1
|
83
|
+
t = type.first
|
52
84
|
|
53
|
-
|
54
|
-
|
55
|
-
# methods that include type checking. The type of this
|
56
|
-
# child must be a subclass of the ASTNode class.
|
57
|
-
def self.child(name, type)
|
58
|
-
if type.is_a?(Array) and type.length == 1
|
59
|
-
t = type.first
|
85
|
+
elsif type.is_a?(Class)
|
86
|
+
t = type
|
60
87
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
else
|
65
|
-
raise Exception, 'Child and Value types must be a class name or an array with a single class name element.'
|
66
|
-
end
|
67
|
-
|
68
|
-
# Check to make sure that type is a subclass of
|
69
|
-
# ASTNode.
|
70
|
-
if not RLTK::subclass_of?(t, ASTNode)
|
71
|
-
raise Exception, "A child's type specification must be a subclass of ASTNode."
|
72
|
-
end
|
73
|
-
|
74
|
-
@child_names << name
|
75
|
-
self.define_accessor(name, type, true)
|
88
|
+
else
|
89
|
+
raise 'Child and Value types must be a class name or an array with a single class name element.'
|
76
90
|
end
|
77
91
|
|
78
|
-
#
|
79
|
-
|
80
|
-
|
92
|
+
# Check to make sure that type is a subclass of
|
93
|
+
# ASTNode.
|
94
|
+
if not t.subclass_of?(ASTNode)
|
95
|
+
raise "A child's type specification must be a subclass of ASTNode."
|
81
96
|
end
|
82
97
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
@child_names << name
|
99
|
+
define_accessor(name, type, true)
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [Array<Symbol>] Array of the names of this node class's children.
|
103
|
+
def child_names
|
104
|
+
@child_names
|
105
|
+
end
|
106
|
+
|
107
|
+
# This method defines a type checking accessor named *name*
|
108
|
+
# with type *type*.
|
109
|
+
#
|
110
|
+
# @param [String, Symbol] name Name of accessor.
|
111
|
+
# @param [Class] type Class used for type checking.
|
112
|
+
# @param [Boolean] set_parent Set the parent variable or not.
|
113
|
+
#
|
114
|
+
# @return [void]
|
115
|
+
def define_accessor(name, type, set_parent = false)
|
116
|
+
ivar_name = ('@' + name.to_s).to_sym
|
117
|
+
|
118
|
+
define_method(name) do
|
119
|
+
self.instance_variable_get(ivar_name)
|
120
|
+
end
|
121
|
+
|
122
|
+
if type.is_a?(Class)
|
123
|
+
if set_parent
|
124
|
+
define_method((name.to_s + '=').to_sym) do |value|
|
125
|
+
if value.is_a?(type) or value == nil
|
126
|
+
self.instance_variable_set(ivar_name, value)
|
103
127
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
self.instance_variable_set(ivar_name, value)
|
108
|
-
|
109
|
-
else
|
110
|
-
raise TypeMismatch.new(type, value.class)
|
111
|
-
end
|
128
|
+
value.parent = self if value
|
129
|
+
else
|
130
|
+
raise TypeMismatch.new(type, value.class)
|
112
131
|
end
|
113
132
|
end
|
114
133
|
|
115
134
|
else
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
define_method((name.to_s + '=').to_sym) do |value|
|
120
|
-
if value.inject(true) { |m, o| m and o.is_a?(type) }
|
121
|
-
self.instance_variable_set(ivar_name, value)
|
135
|
+
define_method((name.to_s + '=').to_sym) do |value|
|
136
|
+
if value.is_a?(type) or value == nil
|
137
|
+
self.instance_variable_set(ivar_name, value)
|
122
138
|
|
123
|
-
|
124
|
-
|
125
|
-
raise TypeMismatch.new(type, value.class)
|
126
|
-
end
|
139
|
+
else
|
140
|
+
raise TypeMismatch.new(type, value.class)
|
127
141
|
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
else
|
146
|
+
type = type.first
|
147
|
+
|
148
|
+
if set_parent
|
149
|
+
define_method((name.to_s + '=').to_sym) do |value|
|
150
|
+
if value.inject(true) { |m, o| m and o.is_a?(type) }
|
151
|
+
self.instance_variable_set(ivar_name, value)
|
128
152
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
self.instance_variable_set(ivar_name, value)
|
133
|
-
|
134
|
-
else
|
135
|
-
raise TypeMismatch.new(type, value.class)
|
136
|
-
end
|
153
|
+
value.each { |c| c.parent = self }
|
154
|
+
else
|
155
|
+
raise TypeMismatch.new(type, value.class)
|
137
156
|
end
|
138
157
|
end
|
139
158
|
|
159
|
+
else
|
160
|
+
define_method((name.to_s + '=').to_sym) do |value|
|
161
|
+
if value.inject(true) { |m, o| m and o.is_a?(type) }
|
162
|
+
self.instance_variable_set(ivar_name, value)
|
163
|
+
|
164
|
+
else
|
165
|
+
raise TypeMismatch.new(type, value.class)
|
166
|
+
end
|
167
|
+
end
|
140
168
|
end
|
141
169
|
end
|
170
|
+
end
|
171
|
+
private :define_accessor
|
172
|
+
|
173
|
+
# Defined a value for this AST class and its subclasses.
|
174
|
+
# The name of the value will be used to define accessor
|
175
|
+
# methods that include type checking. The type of this
|
176
|
+
# value must NOT be a subclass of the ASTNode class.
|
177
|
+
#
|
178
|
+
# @param [String, Symbol] name Name of value.
|
179
|
+
# @param [Class] type Type of value. Must NOT be a subclass of ASTNode.
|
180
|
+
#
|
181
|
+
# @return [void]
|
182
|
+
def value(name, type)
|
183
|
+
if type.is_a?(Array) and type.length == 1
|
184
|
+
t = type.first
|
142
185
|
|
143
|
-
|
144
|
-
|
145
|
-
# methods that include type checking. The type of this
|
146
|
-
# value must NOT be a subclass of the ASTNode class.
|
147
|
-
def self.value(name, type)
|
148
|
-
if type.is_a?(Array) and type.length == 1
|
149
|
-
t = type.first
|
186
|
+
elsif type.is_a?(Class)
|
187
|
+
t = type
|
150
188
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
else
|
155
|
-
raise Exception, 'Child and Value types must be a class name or an array with a single class name element.'
|
156
|
-
end
|
157
|
-
|
158
|
-
# Check to make sure that type is NOT a subclass of
|
159
|
-
# ASTNode.
|
160
|
-
if RLTK::subclass_of?(t, ASTNode)
|
161
|
-
raise Exception, "A value's type specification must NOT be a subclass of ASTNode."
|
162
|
-
end
|
163
|
-
|
164
|
-
@value_names << name
|
165
|
-
self.define_accessor(name, type)
|
189
|
+
else
|
190
|
+
raise 'Child and Value types must be a class name or an array with a single class name element.'
|
166
191
|
end
|
167
192
|
|
168
|
-
#
|
169
|
-
|
170
|
-
|
193
|
+
# Check to make sure that type is NOT a subclass of
|
194
|
+
# ASTNode.
|
195
|
+
if t.subclass_of?(ASTNode)
|
196
|
+
raise "A value's type specification must NOT be a subclass of ASTNode."
|
171
197
|
end
|
198
|
+
|
199
|
+
@value_names << name
|
200
|
+
define_accessor(name, type)
|
201
|
+
end
|
202
|
+
|
203
|
+
# @return [Array<Symbol>] Array of the names of this node class's values.
|
204
|
+
def value_names
|
205
|
+
@value_names
|
172
206
|
end
|
173
207
|
end
|
174
208
|
|
@@ -177,31 +211,39 @@ module RLTK # :nodoc:
|
|
177
211
|
####################
|
178
212
|
|
179
213
|
# Used for AST comparison, this function will return true if the two
|
180
|
-
# nodes are of the same class and all of their values and children
|
181
|
-
# equal.
|
214
|
+
# nodes are of the same class and all of their values and children
|
215
|
+
# are equal.
|
216
|
+
#
|
217
|
+
# @param [ASTNode] other The ASTNode to compare to.
|
218
|
+
#
|
219
|
+
# @return [Boolean]
|
182
220
|
def ==(other)
|
183
221
|
self.class == other.class and self.values == other.values and self.children == other.children
|
184
222
|
end
|
185
223
|
|
186
|
-
#
|
224
|
+
# @return [Object] Note with the name *key*.
|
187
225
|
def [](key)
|
188
226
|
@notes[key]
|
189
227
|
end
|
190
228
|
|
191
|
-
# Sets the note named
|
229
|
+
# Sets the note named *key* to *value*.
|
192
230
|
def []=(key, value)
|
193
231
|
@notes[key] = value
|
194
232
|
end
|
195
233
|
|
196
|
-
#
|
234
|
+
# @return [Array<ASTNode>] Array of this node's children.
|
197
235
|
def children
|
198
236
|
self.class.child_names.map { |name| self.send(name) }
|
199
237
|
end
|
200
238
|
|
201
239
|
# Assigns an array of AST nodes as the children of this node.
|
240
|
+
#
|
241
|
+
# @param [Array<ASTNode>] children Children to be assigned to this node.
|
242
|
+
#
|
243
|
+
# @return [void]
|
202
244
|
def children=(children)
|
203
245
|
if children.length != self.class.child_names.length
|
204
|
-
raise
|
246
|
+
raise 'Wrong number of children specified.'
|
205
247
|
end
|
206
248
|
|
207
249
|
self.class.child_names.each_with_index do |name, i|
|
@@ -209,8 +251,11 @@ module RLTK # :nodoc:
|
|
209
251
|
end
|
210
252
|
end
|
211
253
|
|
212
|
-
# Removes the note
|
254
|
+
# Removes the note *key* from this node. If the *recursive* argument
|
213
255
|
# is true it will also remove the note from the node's children.
|
256
|
+
#
|
257
|
+
# @param [Object] key The key of the note to remove.
|
258
|
+
# @param [Boolean] recursive Do a recursive removal or not.
|
214
259
|
def delete_note(key, recursive = true)
|
215
260
|
if recursive
|
216
261
|
self.children.each do |child|
|
@@ -228,15 +273,16 @@ module RLTK # :nodoc:
|
|
228
273
|
end
|
229
274
|
|
230
275
|
# An iterator over the node's children.
|
276
|
+
#
|
277
|
+
# @return [void]
|
231
278
|
def each
|
232
279
|
self.children.each { |c| yield c }
|
233
280
|
end
|
234
281
|
|
235
|
-
# Tests to see if a note named
|
282
|
+
# Tests to see if a note named *key* is present at this node.
|
236
283
|
def has_note?(key)
|
237
284
|
@notes.has_key?(key)
|
238
285
|
end
|
239
|
-
|
240
286
|
alias :'note?' :'has_note?'
|
241
287
|
|
242
288
|
# Instantiates a new ASTNode object. The arguments to this method are
|
@@ -245,9 +291,11 @@ module RLTK # :nodoc:
|
|
245
291
|
# pass the values in as the first two arguments (in the order they
|
246
292
|
# were declared) and then the children as the remaining arguments (in
|
247
293
|
# the order they were declared).
|
294
|
+
#
|
295
|
+
# @param [Array<Object>] objects The values and children of this node.
|
248
296
|
def initialize(*objects)
|
249
297
|
if self.class == RLTK::ASTNode
|
250
|
-
raise
|
298
|
+
raise 'Attempting to instantiate the RLTK::ASTNode class.'
|
251
299
|
else
|
252
300
|
@notes = Hash.new()
|
253
301
|
@parent = nil
|
@@ -260,24 +308,28 @@ module RLTK # :nodoc:
|
|
260
308
|
end
|
261
309
|
|
262
310
|
# Maps the children of the ASTNode from one value to another.
|
311
|
+
#
|
312
|
+
# @return [void]
|
263
313
|
def map
|
264
314
|
self.children = self.children.map { |c| yield c }
|
265
315
|
end
|
266
316
|
|
267
|
-
#
|
317
|
+
# @return [ASTNode] Root of the abstract syntax tree.
|
268
318
|
def root
|
269
319
|
if @parent then @parent.root else self end
|
270
320
|
end
|
271
321
|
|
272
|
-
#
|
322
|
+
# @return [Array<Object>] Array of this node's values.
|
273
323
|
def values
|
274
324
|
self.class.value_names.map { |name| self.send(name) }
|
275
325
|
end
|
276
326
|
|
277
327
|
# Assigns an array of objects as the values of this node.
|
328
|
+
#
|
329
|
+
# @param [Array<Object>] values The values to be assigned to this node.
|
278
330
|
def values=(values)
|
279
331
|
if values.length != self.class.value_names.length
|
280
|
-
raise
|
332
|
+
raise 'Wrong number of values specified.'
|
281
333
|
end
|
282
334
|
|
283
335
|
self.class.value_names.each_with_index do |name, i|
|