Class: Rubex::SymbolTable::Scope::BeginBlock
- Inherits:
-
Object
- Object
- Rubex::SymbolTable::Scope::BeginBlock
- Defined in:
- lib/rubex/symbol_table/scope.rb
Overview
class Local
Direct Known Subclasses
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#outer_scope ⇒ Object
readonly
Returns the value of attribute outer_scope.
Instance Method Summary collapse
-
#initialize(name, outer_scope) ⇒ BeginBlock
constructor
A new instance of BeginBlock.
-
#method_missing(meth, *args, &block) ⇒ Object
IMPORTANT NOTE TO PROGRAMMER:.
- #upgrade_symbols_to_global ⇒ Object
Constructor Details
#initialize(name, outer_scope) ⇒ BeginBlock
Returns a new instance of BeginBlock.
264 265 266 267 268 |
# File 'lib/rubex/symbol_table/scope.rb', line 264 def initialize name, outer_scope @outer_scope = outer_scope @name = name @block_entries = [] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, &block) ⇒ Object
IMPORTANT NOTE TO PROGRAMMER:
A problem with the BeginBlock is that in the Ruby world, it must share scope with the method above and below it. However, when translating to C, the begin block must be put inside its own C function, which is then sent as a callback to rb_protect().
The same as above applies to a no_gil block, which is why the NoGilBlock (defined below) inherits from this class and completely imitates its behaviour.
As a result, it is necesary to ‘upgrade’ the local variables present inside the begin block to C global variables so that they can be shared between the callback C function encapsulating the begin block and the ruby method that has a begin block defined inside it.
Now, since variables must be shared, it is also necessary to share the scopes between these functions. Therefore, the BeginBlock scope uses method_missing to capture whatever methods calls it has received and redirect those to @outer_scope, which is the scope of the method that contains the begin block. Whenever a method call to @outer_scope returns a SymbolTable::Entry object, that object is read to check if it is a variable. If yes, it is added into the @block_entries Array which stores the entries that need to be upgraded to C global variables.
Now as a side effect of this behaviour, the various *_entries Arrays of @outer_scope get carried forward into this begin block callback. Therefore these variables get declared inside the begin block callback as well. So whenever one of these Arrays is called for this particular scope, we preturn an empty array so that nothing gets declared.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/rubex/symbol_table/scope.rb', line 313 def method_missing meth, *args, &block return [] if meth == :var_entries ret = @outer_scope.send(meth, *args, &block) if ret.is_a?(Rubex::SymbolTable::Entry) if !ret.extern? if !ret.type.c_function? && !ret.type.ruby_method? && !ret.type.ruby_class? @block_entries << ret end end end ret end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
262 263 264 |
# File 'lib/rubex/symbol_table/scope.rb', line 262 def name @name end |
#outer_scope ⇒ Object (readonly)
Returns the value of attribute outer_scope.
262 263 264 |
# File 'lib/rubex/symbol_table/scope.rb', line 262 def outer_scope @outer_scope end |
Instance Method Details
#upgrade_symbols_to_global ⇒ Object
270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/rubex/symbol_table/scope.rb', line 270 def upgrade_symbols_to_global @block_entries.uniq! @block_entries.each do |entry| @outer_scope.global_entries << entry end remove_global_from_local_entries @outer_scope.global_entries.each do |entry| entry.c_name = Rubex::GLOBAL_PREFIX + @name + entry.c_name end end |