Class: Mirah::JVM::Compiler::Base
- Inherits:
-
SimpleNodeVisitor
- Object
- SimpleNodeVisitor
- Mirah::JVM::Compiler::Base
- Includes:
- Logging::Logged
- Defined in:
- lib/mirah/jvm/compiler/base.rb
Direct Known Subclasses
Defined Under Namespace
Classes: CompilationError, ScriptScanner
Constant Summary
Constants included from Logging::Logged
Instance Attribute Summary collapse
-
#class ⇒ Object
Returns the value of attribute class.
-
#filename ⇒ Object
Returns the value of attribute filename.
-
#method ⇒ Object
Returns the value of attribute method.
-
#static ⇒ Object
Returns the value of attribute static.
Instance Method Summary collapse
- #base_define_method(node) ⇒ Object
- #begin_main ⇒ Object
- #containing_scope(node) ⇒ Object
-
#create_method_builder(name, node, static, exceptions, return_type, arg_types) ⇒ Object
arg_types must be an Array.
- #declared_captures(binding = nil) ⇒ Object
- #defaultNode(node, expression) ⇒ Object
- #error(message, node) ⇒ Object
- #finish_main ⇒ Object
- #generate ⇒ Object
- #get_binding(type) ⇒ Object
- #get_scope(node) ⇒ Object
- #inferred_type(node) ⇒ Object
-
#initialize(config, scoper, typer) ⇒ Base
constructor
A new instance of Base.
- #introduced_scope(node) ⇒ Object
- #logger_name ⇒ Object
- #scoped_body(scope, expression) ⇒ Object
- #scoped_local_name(name, scope = nil) ⇒ Object
- #supports_invokedynamic? ⇒ Boolean
- #target_jvm_version ⇒ Object
- #toplevel_class ⇒ Object
- #visit(node, expression) ⇒ Object
- #visitArguments(args, expression) ⇒ Object
- #visitCharLiteral(node, expression) ⇒ Object
- #visitClassAppendSelf(node, expression) ⇒ Object
- #visitClassDefinition(class_def, expression) ⇒ Object
- #visitConstructorDefinition(node, expression) ⇒ Object
- #visitFixnum(node, expression) ⇒ Object (also: #visitFloat)
- #visitImplicitSelf(node, expression) ⇒ Object
- #visitImport(node, expression) ⇒ Object
- #visitMacroDefinition(node, expression) ⇒ Object
- #visitNodeList(body, expression) ⇒ Object
- #visitNoop(node, expression) ⇒ Object
- #visitPackage(node, expression) ⇒ Object
- #visitScript(script, expression) ⇒ Object
- #visitSelf(node, expression) ⇒ Object
- #visitStaticMethodDefinition(mdef, expression) ⇒ Object
- #visitUnquote(node, expression) ⇒ Object
- #with(vars) ⇒ Object
Methods included from Logging::Logged
#info, #log, #logger, #logging?, #vlog, #warning
Constructor Details
#initialize(config, scoper, typer) ⇒ Base
Returns a new instance of Base.
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/mirah/jvm/compiler/base.rb', line 35 def initialize(config, scoper, typer) super() @config = config @jump_scope = [] @bindings = Hash.new {|h, type| h[type] = type.define(@file)} @captured_locals = Hash.new {|h, binding| h[binding] = {}} @self_scope = nil @scoper = typer.scoper @typer = typer end |
Instance Attribute Details
#class ⇒ Object
Returns the value of attribute class.
25 26 27 |
# File 'lib/mirah/jvm/compiler/base.rb', line 25 def class @class end |
#filename ⇒ Object
Returns the value of attribute filename.
25 26 27 |
# File 'lib/mirah/jvm/compiler/base.rb', line 25 def filename @filename end |
#method ⇒ Object
Returns the value of attribute method.
25 26 27 |
# File 'lib/mirah/jvm/compiler/base.rb', line 25 def method @method end |
#static ⇒ Object
Returns the value of attribute static.
25 26 27 |
# File 'lib/mirah/jvm/compiler/base.rb', line 25 def static @static end |
Instance Method Details
#base_define_method(node) ⇒ Object
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/mirah/jvm/compiler/base.rb', line 212 def base_define_method(node) name = node.name.identifier.sub(/=$/, '_set') args = visit(node.arguments, true) is_static = self.static || node.kind_of?(StaticMethodDefinition) if name == "initialize" && is_static name = "<clinit>" end arg_types = args.map { |arg| inferred_type(arg) } return_type = inferred_type(node).return_type exceptions = [] # TODO with :static => is_static, :current_scope => introduced_scope(node) do method = create_method_builder(name, node, @static, exceptions, return_type, arg_types) annotate(method, node.annotations) yield method, arg_types end arg_types_for_opt = [] args_for_opt = [] if args args.each do |arg| if AST::OptionalArgument === arg new_args = arg_types_for_opt method = create_method_builder(name, node, @static, exceptions, return_type, new_args) with :method => method do log "Starting new method #{name}(#{arg_types_for_opt})" annotate(method, node.annotations) @method.start define_optarg_chain(name, arg, return_type, args_for_opt, arg_types_for_opt) @method.stop end end arg_types_for_opt << inferred_type(arg) args_for_opt << arg end end end |
#begin_main ⇒ Object
199 |
# File 'lib/mirah/jvm/compiler/base.rb', line 199 def begin_main; end |
#containing_scope(node) ⇒ Object
74 75 76 77 78 79 80 81 |
# File 'lib/mirah/jvm/compiler/base.rb', line 74 def containing_scope(node) scope = get_scope(node) name = node.name.identifier while (!scope.shadowed?(name) && scope.parent && scope.parent.include?(name)) scope = scope.parent end scope end |
#create_method_builder(name, node, static, exceptions, return_type, arg_types) ⇒ Object
arg_types must be an Array
203 204 205 206 207 208 209 210 |
# File 'lib/mirah/jvm/compiler/base.rb', line 203 def create_method_builder(name, node, static, exceptions, return_type, arg_types) return_type = nil if return_type.name == ':unreachable' visibility = :public # TODO flags = BiteScript::ASM::Opcodes::ACC_PUBLIC flags |= BiteScript::ASM::Opcodes::ACC_STATIC if static flags |= BiteScript::ASM::Opcodes::ACC_ABSTRACT if node.annotated_abstract? @class.method(flags, name.to_s, [return_type, *arg_types], exceptions) end |
#declared_captures(binding = nil) ⇒ Object
399 400 401 |
# File 'lib/mirah/jvm/compiler/base.rb', line 399 def declared_captures(binding=nil) @captured_locals[binding || @binding] end |
#defaultNode(node, expression) ⇒ Object
54 55 56 |
# File 'lib/mirah/jvm/compiler/base.rb', line 54 def defaultNode(node, expression) raise ArgumentError, "Can't compile node #{node}" end |
#error(message, node) ⇒ Object
91 92 93 |
# File 'lib/mirah/jvm/compiler/base.rb', line 91 def error(, node) raise CompilationError.new(, node) end |
#finish_main ⇒ Object
200 |
# File 'lib/mirah/jvm/compiler/base.rb', line 200 def finish_main; end |
#generate ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/mirah/jvm/compiler/base.rb', line 99 def generate log "Generating #{output_type}..." @file.generate do |filename, builder| log " #{builder.class_name}" if block_given? yield filename, builder else File.open(filename, 'wb') {|f| f.write(builder.generate)} end end log "...done!" end |
#get_binding(type) ⇒ Object
395 396 397 |
# File 'lib/mirah/jvm/compiler/base.rb', line 395 def get_binding(type) @bindings[type] end |
#get_scope(node) ⇒ Object
66 67 68 |
# File 'lib/mirah/jvm/compiler/base.rb', line 66 def get_scope(node) @scoper.get_scope(node) end |
#inferred_type(node) ⇒ Object
83 84 85 86 87 88 89 |
# File 'lib/mirah/jvm/compiler/base.rb', line 83 def inferred_type(node) begin @typer.get_inferred_type(node).resolve rescue Exception => ex raise Mirah::InternalCompilerError.wrap(ex, node) end end |
#introduced_scope(node) ⇒ Object
70 71 72 |
# File 'lib/mirah/jvm/compiler/base.rb', line 70 def introduced_scope(node) @scoper.get_introduced_scope(node) end |
#logger_name ⇒ Object
31 32 33 |
# File 'lib/mirah/jvm/compiler/base.rb', line 31 def logger_name "org.mirah.ruby.JVM.Compiler.Base" end |
#scoped_body(scope, expression) ⇒ Object
336 337 338 |
# File 'lib/mirah/jvm/compiler/base.rb', line 336 def scoped_body(scope, expression) body(scope, expression) end |
#scoped_local_name(name, scope = nil) ⇒ Object
340 341 342 343 344 345 346 |
# File 'lib/mirah/jvm/compiler/base.rb', line 340 def scoped_local_name(name, scope=nil) if scope.nil? || scope == @current_scope name else "#{name}$#{scope.object_id}" end end |
#supports_invokedynamic? ⇒ Boolean
50 51 52 |
# File 'lib/mirah/jvm/compiler/base.rb', line 50 def supports_invokedynamic? @config.supports_invokedynamic? end |
#target_jvm_version ⇒ Object
46 47 48 |
# File 'lib/mirah/jvm/compiler/base.rb', line 46 def target_jvm_version @config.target_jvm_version end |
#toplevel_class ⇒ Object
95 96 97 |
# File 'lib/mirah/jvm/compiler/base.rb', line 95 def toplevel_class @class = @type.define(@file) end |
#visit(node, expression) ⇒ Object
58 59 60 61 62 63 64 |
# File 'lib/mirah/jvm/compiler/base.rb', line 58 def visit(node, expression) begin node.accept(self, expression) rescue Exception => ex raise Mirah::InternalCompilerError.wrap(ex, node) end end |
#visitArguments(args, expression) ⇒ Object
281 282 283 284 285 286 287 288 289 |
# File 'lib/mirah/jvm/compiler/base.rb', line 281 def visitArguments(args, expression) result = [] args.required.each {|arg| result << arg} args.optional.each {|arg| result << arg} result << args.rest if args.rest args.required2.each {|arg| result << arg} result << args.block if args.block result end |
#visitCharLiteral(node, expression) ⇒ Object
357 358 359 360 361 |
# File 'lib/mirah/jvm/compiler/base.rb', line 357 def visitCharLiteral(node, expression) if expression inferred_type(node).literal(method, node.value) end end |
#visitClassAppendSelf(node, expression) ⇒ Object
326 327 328 329 330 |
# File 'lib/mirah/jvm/compiler/base.rb', line 326 def visitClassAppendSelf(node, expression) with :static => true, :current_scope => introduced_scope(node) do visit(node.body, expression) end end |
#visitClassDefinition(class_def, expression) ⇒ Object
270 271 272 273 274 275 276 277 278 279 |
# File 'lib/mirah/jvm/compiler/base.rb', line 270 def visitClassDefinition(class_def, expression) log "Compiling class #{class_def.name.identifier}" with(:type => inferred_type(class_def), :class => inferred_type(class_def).define(@file), :static => false) do annotate(@class, class_def.annotations) visit(class_def.body, false) if class_def.body @class.stop end end |
#visitConstructorDefinition(node, expression) ⇒ Object
258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/mirah/jvm/compiler/base.rb', line 258 def visitConstructorDefinition(node, expression) args = visit(node.arguments, true) arg_types = args.map { |arg| inferred_type(arg) } exceptions = [] # node.signature[:throws] visibility = :public # node.visibility method = @class.build_constructor(visibility, exceptions, *arg_types) annotate(method, node.annotations) with :current_scope => introduced_scope(node) do yield(method, args) end end |
#visitFixnum(node, expression) ⇒ Object Also known as: visitFloat
351 352 353 354 355 |
# File 'lib/mirah/jvm/compiler/base.rb', line 351 def visitFixnum(node, expression) if expression inferred_type(node).literal(method, node.value) end end |
#visitImplicitSelf(node, expression) ⇒ Object
377 378 379 |
# File 'lib/mirah/jvm/compiler/base.rb', line 377 def visitImplicitSelf(node, expression) visitSelf(node, expression) end |
#visitImport(node, expression) ⇒ Object
348 349 |
# File 'lib/mirah/jvm/compiler/base.rb', line 348 def visitImport(node, expression) end |
#visitMacroDefinition(node, expression) ⇒ Object
153 154 155 |
# File 'lib/mirah/jvm/compiler/base.rb', line 153 def visitMacroDefinition(node, expression) # ignore. It was already compiled end |
#visitNodeList(body, expression) ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/mirah/jvm/compiler/base.rb', line 295 def visitNodeList(body, expression) saved_self = @self_scope new_scope = introduced_scope(body) if new_scope declare_locals(new_scope) if new_scope != @self_scope if new_scope.self_node && new_scope.self_node != :self # FIXME This is a horrible hack! # Instead we should eliminate unused self's. unless new_scope.self_type.name == 'mirah.impl.Builtin' local_assign( new_scope, 'self', new_scope.self_type, false, new_scope.self_node) end end @self_scope = new_scope end end # all except the last element in a body of code is treated as a statement i, last = 0, body.size - 1 while i < last visit(body.get(i), false) i += 1 end if last >= 0 yield body.get(last) else yield nil end @self_scope = saved_self end |
#visitNoop(node, expression) ⇒ Object
196 197 |
# File 'lib/mirah/jvm/compiler/base.rb', line 196 def visitNoop(node, expression) end |
#visitPackage(node, expression) ⇒ Object
332 333 334 |
# File 'lib/mirah/jvm/compiler/base.rb', line 332 def visitPackage(node, expression) visit(node.body, expression) if node.body end |
#visitScript(script, expression) ⇒ Object
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 190 191 192 193 194 |
# File 'lib/mirah/jvm/compiler/base.rb', line 157 def visitScript(script, expression) @static = true @filename = File.basename(script.position.source.name) classname = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(@filename) @type = @typer.type_system.type(get_scope(script), classname) @file = file_builder(@filename) body = script.body scanner = ScriptScanner.new scanner.scan(body, expression) need_class = scanner.found_method || scanner.found_other if need_class @class = @type.define(@file) if scanner.found_other # Generate the main method with :method => @class.main do log "Starting main method" @method.start @current_scope = get_scope(script) declare_locals(@current_scope) begin_main prepare_binding(script) do visit(body, false) end finish_main @method.stop end log "Main method complete!" else visit(body, false) end @class.stop else visit(body, false) end end |
#visitSelf(node, expression) ⇒ Object
365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/mirah/jvm/compiler/base.rb', line 365 def visitSelf(node, expression) if expression set_position(node.position) scope = get_scope(node) if scope.self_node && scope.self_node != :self local(scope, 'self', scope.self_type) else real_self end end end |
#visitStaticMethodDefinition(mdef, expression) ⇒ Object
291 292 293 |
# File 'lib/mirah/jvm/compiler/base.rb', line 291 def visitStaticMethodDefinition(mdef, expression) visitMethodDefinition(mdef, expression) end |
#visitUnquote(node, expression) ⇒ Object
381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'lib/mirah/jvm/compiler/base.rb', line 381 def visitUnquote(node, expression) body = node.nodes i, last = 0, body.size - 1 while i < last visit(body.get(i), false) i += 1 end if last >= 0 visit(body.get(last), expression) else visitImplicitNil(node, expression) end end |
#with(vars) ⇒ Object
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/mirah/jvm/compiler/base.rb', line 403 def with(vars) orig_values = {} begin vars.each do |name, new_value| name = "@#{name}" orig_values[name] = instance_variable_get name instance_variable_set name, new_value end yield ensure orig_values.each do |name, value| instance_variable_set name, value end end end |