Class: Rubex::AST::Node::Base
Instance Attribute Summary collapse
Instance Method Summary
collapse
#declare_carrays, #declare_ruby_objects, #declare_temps, #declare_types, #declare_vars, #sue_footer, #sue_header, #write_char_2_ruby_str_code, #write_char_2_ruby_str_header, #write_usability_functions_code, #write_usability_functions_header, #write_usability_macros
Constructor Details
#initialize(statements, file_name) ⇒ Base
Returns a new instance of Base.
9
10
11
12
13
|
# File 'lib/rubex/ast/node.rb', line 9
def initialize(statements, file_name)
@statements = statements.flatten
@file_name = file_name
@dependent_files = []
end
|
Instance Attribute Details
#file_name ⇒ Object
Returns the value of attribute file_name.
7
8
9
|
# File 'lib/rubex/ast/node.rb', line 7
def file_name
@file_name
end
|
#statements ⇒ Object
Returns the value of attribute statements.
7
8
9
|
# File 'lib/rubex/ast/node.rb', line 7
def statements
@statements
end
|
Instance Method Details
#==(other) ⇒ Object
15
16
17
|
# File 'lib/rubex/ast/node.rb', line 15
def ==(other)
self.class == other.class
end
|
#add_top_statements_to_object_scope ⇒ Object
Scan all the statements that do not belong to any particular class
(meaning that they belong to Object) and add them to the Object class,
which becomes the class from which all other classes will inherit from.
Top-level statements that do not belong inside classes and which do not
have any relevance inside a class at the level of a C extension are
added to a different array and are analysed differently. For example
'require' statements that are top level statements but cannot be 'defined'
inside the Init_ method the way a ruby class or method can be. These are
stored in @outside_statements.
If the user defines multiple Object classes, they will share the same @scope
object and will therefore have accessible members between each other. Since
Ruby also allows users to open classes whenever and wherever they want, this
behaviour is conformant with actual Ruby behaviour. It also implies that a
FileNode can basically create an Object class of its own and the scope will
shared between FileNode and MainNode and other FileNodes as long as the FileNode
shares the same @scope object.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# File 'lib/rubex/ast/node.rb', line 47
def add_top_statements_to_object_scope
temp = []
combined_statements = []
@outside_statements = []
@statements.each do |stmt|
if stmt.is_a?(TopStatement::Klass) || stmt.is_a?(TopStatement::CBindings)
if !temp.empty?
object_klass = TopStatement::Klass.new('Object', @scope, temp)
combined_statements << object_klass
end
combined_statements << stmt
temp = []
elsif outside_statement?(stmt)
@outside_statements << stmt
elsif stmt.is_a?(Node::FileNode)
combined_statements << stmt
else
temp << stmt
end
end
unless temp.empty?
combined_statements << TopStatement::Klass.new('Object', @scope, temp)
end
@statements = combined_statements
end
|
#analyse_statement ⇒ Object
19
20
21
22
23
24
25
26
27
|
# File 'lib/rubex/ast/node.rb', line 19
def analyse_statement
@statements.each do |stat|
@dependent_files << stat.file_name if stat.is_a?(Node::FileNode)
stat.analyse_statement @scope
end
@outside_statements.each do |stmt|
stmt.analyse_statement @scope
end
end
|
#c_name_for_class(name) ⇒ Object
#call_dependent_init_methods(code) ⇒ Object
276
277
278
279
280
281
|
# File 'lib/rubex/ast/node.rb', line 276
def call_dependent_init_methods(code)
@dependent_files.each do |dep|
code << "Init_#{dep}();"
code.nl
end
end
|
#create_symtab_entries_for_top_statements(s) ⇒ Object
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
# File 'lib/rubex/ast/node.rb', line 156
def create_symtab_entries_for_top_statements(s)
@scope = s
@statements.each do |stat|
stat.create_symtab_entries_for_top_statements(@scope) if stat.is_a?(Node::FileNode)
next unless stat.is_a? Rubex::AST::TopStatement::Klass
name = stat.name
if name != 'Object'
ancestor_entry = @scope.find(stat.ancestor)
if !ancestor_entry && Rubex::DEFAULT_CLASS_MAPPINGS[stat.ancestor]
ancestor_c_name = Rubex::DEFAULT_CLASS_MAPPINGS[stat.ancestor]
ancestor_scope = object_or_stdlib_klass_scope stat.ancestor
@scope.add_ruby_class(name: stat.ancestor, c_name: ancestor_c_name,
scope: @scope, ancestor: nil, extern: true)
else
ancestor_scope = ancestor_entry&.type&.scope || @scope
end
klass_scope = Rubex::SymbolTable::Scope::Klass.new(
name, ancestor_scope
)
else
ancestor_scope = @scope
klass_scope = @scope
end
c_name = c_name_for_class name
@scope.add_ruby_class(name: name, c_name: c_name, scope: klass_scope,
ancestor: ancestor_scope, extern: false)
end
end
|
#declare_unique_types(header) ⇒ Object
81
82
83
84
85
86
87
88
|
# File 'lib/rubex/ast/node.rb', line 81
def declare_unique_types
types = []
@statements.grep(Rubex::AST::TopStatement::Klass).each do |klass|
types.concat klass.scope.type_entries
end
types.uniq!
declare_types , types
end
|
#define_classes(code) ⇒ Object
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
# File 'lib/rubex/ast/node.rb', line 225
def define_classes(code)
@statements.each do |top_stmt|
if top_stmt.is_a?(TopStatement::Klass) && top_stmt.name != 'Object'
entry = top_stmt.entry
ancestor_entry = @scope.find top_stmt.ancestor.name
c_name = ancestor_entry ? ancestor_entry.c_name : 'rb_cObject'
rhs = "rb_define_class(\"#{entry.name}\", #{c_name})"
code.init_variable lhs: entry.c_name, rhs: rhs
end
next unless top_stmt.is_a?(TopStatement::AttachedKlass)
entry = top_stmt.entry
scope = top_stmt.scope
alloc = ''
alloc << "rb_define_alloc_func(#{entry.c_name}, "
alloc << "#{scope.find(TopStatement::AttachedKlass::ALLOC_FUNC_NAME).c_name});\n"
code << alloc
end
code.nl
end
|
#define_instance_and_singleton_methods_for_all_classes(code) ⇒ Object
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
# File 'lib/rubex/ast/node.rb', line 249
def define_instance_and_singleton_methods_for_all_classes(code)
@statements.each do |top_stmt|
next unless top_stmt.is_a? TopStatement::Klass
entry = @scope.find top_stmt.name
klass_scope = entry.type.scope
klass_scope.ruby_method_entries.each do |meth|
if meth.singleton?
code.write_singleton_method klass: entry.c_name,
method_name: meth.name, method_c_name: meth.c_name
else
code.write_instance_method klass: entry.c_name,
method_name: meth.name, method_c_name: meth.c_name
end
end
end
end
|
#generate_code(supervisor) ⇒ Object
FIXME: Find a way to eradicate the if statement.
215
216
217
218
219
220
221
222
223
|
# File 'lib/rubex/ast/node.rb', line 215
def generate_code(supervisor)
@statements.each do |stat|
if stat.is_a?(Rubex::AST::Node::FileNode)
stat.generate_code supervisor
else
stat.generate_code supervisor.code(@file_name)
end
end
end
|
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/rubex/ast/node.rb', line 90
def (target_name, )
= target_name.gsub("/", "_").gsub(".", "_").upcase + "_H"
.() do
.write_include Rubex::COMMON_UTILS_FILE
@scope.include_files.each do |name|
<<
if name[0] == '<' && name[-1] == '>'
"#include #{name}\n"
else
"#include \"#{name}\"\n"
end
end
declare_unique_types
write_user_klasses
write_global_variable_declarations
write_function_declarations
.write_func_declaration type: 'void', c_name: init_function,
args: [], static: false
end
end
|
#generate_init_method(code) ⇒ Object
283
284
285
286
287
288
289
290
291
292
293
|
# File 'lib/rubex/ast/node.rb', line 283
def generate_init_method(code)
name = init_function
code.new_line
code. type: 'void', c_name: name, args: [], static: false
code.block do
call_dependent_init_methods(code)
write_outside_statements(code)
define_classes(code)
define_instance_and_singleton_methods_for_all_classes(code)
end
end
|
#init_function ⇒ Object
272
273
274
|
# File 'lib/rubex/ast/node.rb', line 272
def init_function
"Init_#{@file_name}"
end
|
#object_or_stdlib_klass_scope(name) ⇒ Object
191
192
193
194
|
# File 'lib/rubex/ast/node.rb', line 191
def object_or_stdlib_klass_scope(name)
name != 'Object' ? Rubex::SymbolTable::Scope::Klass.new(name, nil) :
@scope
end
|
#outside_statement?(stmt) ⇒ Boolean
TODO: accomodate all sorts of outside stmts like if blocks/while/for etc
77
78
79
|
# File 'lib/rubex/ast/node.rb', line 77
def outside_statement?(stmt)
stmt.is_a?(Statement::Expression)
end
|
#rescan_declarations(_scope) ⇒ Object
207
208
209
210
211
212
|
# File 'lib/rubex/ast/node.rb', line 207
def rescan_declarations(_scope)
@statements.each do |stat|
stat.respond_to?(:rescan_declarations) &&
stat.rescan_declarations(@scope)
end
end
|
#write_function_declarations(code) ⇒ Object
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'lib/rubex/ast/node.rb', line 134
def write_function_declarations(code)
@statements.each do |stmt|
next unless stmt.is_a?(Rubex::AST::TopStatement::Klass)
stmt.scope.ruby_method_entries.each do |entry|
code.(
type: entry.type.type.to_s, c_name: entry.c_name
)
code.colon
end
stmt.scope.c_method_entries.each do |entry|
next if entry.extern?
code.(
type: entry.type.type.to_s,
c_name: entry.c_name,
args: Helpers.create_arg_arrays(entry.type.arg_list)
)
code.colon
end
end
end
|
#write_global_variable_declarations(code) ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
122
|
# File 'lib/rubex/ast/node.rb', line 111
def write_global_variable_declarations(code)
@statements.each do |stmt|
next unless stmt.is_a?(TopStatement::Klass)
stmt.statements.each do |s|
next unless s.is_a?(TopStatement::MethodDef)
s.scope.global_entries.each do |g|
code << "static #{g.type} #{g.c_name};"
code.nl
end
end
end
end
|
#write_outside_statements(code) ⇒ Object
266
267
268
269
270
|
# File 'lib/rubex/ast/node.rb', line 266
def write_outside_statements(code)
@outside_statements.each do |stmt|
stmt.generate_code(code, @scope)
end
end
|
#write_user_klasses(code) ⇒ Object
124
125
126
127
128
129
130
131
132
|
# File 'lib/rubex/ast/node.rb', line 124
def write_user_klasses(code)
code.nl
@scope.ruby_class_entries.each do |klass|
unless Rubex::DEFAULT_CLASS_MAPPINGS.has_key?(klass.name)
code << "VALUE #{klass.c_name};"
code.nl
end
end
end
|