Class: SyntaxTree::YARV::Compiler::RubyVisitor

Inherits:
BasicVisitor
  • Object
show all
Defined in:
lib/syntax_tree/yarv/compiler.rb

Overview

This visitor is responsible for converting Syntax Tree nodes into their corresponding Ruby structures. This is used to convert the operands of some instructions like putobject that push a Ruby object directly onto the stack. It is only used when the entire structure can be represented at compile-time, as opposed to constructed at run-time.

Direct Known Subclasses

Assembler::ObjectVisitor

Defined Under Namespace

Classes: CompilationError

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BasicVisitor

#visit, #visit_all, #visit_child_nodes, visit_method, visit_methods

Class Method Details

.compile(node) ⇒ Object

This will attempt to compile the given node. If it’s possible, then it will return the compiled object. Otherwise it will return nil.



122
123
124
125
# File 'lib/syntax_tree/yarv/compiler.rb', line 122

def self.compile(node)
  node.accept(new)
rescue CompilationError
end

Instance Method Details

#visit_array(node) ⇒ Object



127
128
129
# File 'lib/syntax_tree/yarv/compiler.rb', line 127

def visit_array(node)
  node.contents ? visit_all(node.contents.parts) : []
end

#visit_bare_assoc_hash(node) ⇒ Object Also known as: visit_hash



131
132
133
134
135
136
137
138
# File 'lib/syntax_tree/yarv/compiler.rb', line 131

def visit_bare_assoc_hash(node)
  node.assocs.to_h do |assoc|
    # We can only convert regular key-value pairs. A double splat **
    # operator means it has to be converted at run-time.
    raise CompilationError unless assoc.is_a?(Assoc)
    [visit(assoc.key), visit(assoc.value)]
  end
end

#visit_float(node) ⇒ Object



140
141
142
# File 'lib/syntax_tree/yarv/compiler.rb', line 140

def visit_float(node)
  node.value.to_f
end

#visit_imaginary(node) ⇒ Object



146
147
148
# File 'lib/syntax_tree/yarv/compiler.rb', line 146

def visit_imaginary(node)
  node.value.to_c
end

#visit_int(node) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/syntax_tree/yarv/compiler.rb', line 150

def visit_int(node)
  case (value = node.value)
  when /^0b/
    value[2..].to_i(2)
  when /^0o/
    value[2..].to_i(8)
  when /^0d/
    value[2..].to_i
  when /^0x/
    value[2..].to_i(16)
  else
    value.to_i
  end
end

#visit_label(node) ⇒ Object



165
166
167
# File 'lib/syntax_tree/yarv/compiler.rb', line 165

def visit_label(node)
  node.value.chomp(":").to_sym
end

#visit_mrhs(node) ⇒ Object



169
170
171
# File 'lib/syntax_tree/yarv/compiler.rb', line 169

def visit_mrhs(node)
  visit_all(node.parts)
end

#visit_qsymbols(node) ⇒ Object



173
174
175
# File 'lib/syntax_tree/yarv/compiler.rb', line 173

def visit_qsymbols(node)
  node.elements.map { |element| visit(element).to_sym }
end

#visit_qwords(node) ⇒ Object



177
178
179
# File 'lib/syntax_tree/yarv/compiler.rb', line 177

def visit_qwords(node)
  visit_all(node.elements)
end

#visit_range(node) ⇒ Object



181
182
183
184
# File 'lib/syntax_tree/yarv/compiler.rb', line 181

def visit_range(node)
  left, right = [visit(node.left), visit(node.right)]
  node.operator.value === ".." ? left..right : left...right
end

#visit_rational(node) ⇒ Object



186
187
188
# File 'lib/syntax_tree/yarv/compiler.rb', line 186

def visit_rational(node)
  node.value.to_r
end

#visit_regexp_literal(node) ⇒ Object



190
191
192
193
194
195
196
197
198
# File 'lib/syntax_tree/yarv/compiler.rb', line 190

def visit_regexp_literal(node)
  if node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    Regexp.new(node.parts.first.value, visit_regexp_literal_flags(node))
  else
    # Any interpolation of expressions or variables will result in the
    # regular expression being constructed at run-time.
    raise CompilationError
  end
end

#visit_regexp_literal_flags(node) ⇒ Object

This isn’t actually a visit method, though maybe it should be. It is responsible for converting the set of string options on a regular expression into its equivalent integer.



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/syntax_tree/yarv/compiler.rb', line 203

def visit_regexp_literal_flags(node)
  node
    .options
    .chars
    .inject(0) do |accum, option|
      accum |
        case option
        when "i"
          Regexp::IGNORECASE
        when "x"
          Regexp::EXTENDED
        when "m"
          Regexp::MULTILINE
        else
          raise "Unknown regexp option: #{option}"
        end
    end
end

#visit_symbol_literal(node) ⇒ Object



222
223
224
# File 'lib/syntax_tree/yarv/compiler.rb', line 222

def visit_symbol_literal(node)
  node.value.value.to_sym
end

#visit_symbols(node) ⇒ Object



226
227
228
# File 'lib/syntax_tree/yarv/compiler.rb', line 226

def visit_symbols(node)
  node.elements.map { |element| visit(element).to_sym }
end

#visit_tstring_content(node) ⇒ Object



230
231
232
# File 'lib/syntax_tree/yarv/compiler.rb', line 230

def visit_tstring_content(node)
  node.value
end

#visit_unsupported(_node) ⇒ Object

Raises:



263
264
265
# File 'lib/syntax_tree/yarv/compiler.rb', line 263

def visit_unsupported(_node)
  raise CompilationError
end

#visit_var_ref(node) ⇒ Object

Raises:



234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/syntax_tree/yarv/compiler.rb', line 234

def visit_var_ref(node)
  raise CompilationError unless node.value.is_a?(Kw)

  case node.value.value
  when "nil"
    nil
  when "true"
    true
  when "false"
    false
  else
    raise CompilationError
  end
end

#visit_word(node) ⇒ Object



249
250
251
252
253
254
255
256
257
# File 'lib/syntax_tree/yarv/compiler.rb', line 249

def visit_word(node)
  if node.parts.length == 1 && node.parts.first.is_a?(TStringContent)
    node.parts.first.value
  else
    # Any interpolation of expressions or variables will result in the
    # string being constructed at run-time.
    raise CompilationError
  end
end

#visit_words(node) ⇒ Object



259
260
261
# File 'lib/syntax_tree/yarv/compiler.rb', line 259

def visit_words(node)
  visit_all(node.elements)
end