A prism visitor that builds Sexp objects.

Attributes
Read

This is the name of the file that we are compiling. We set it on every Sexp object that is generated, and also use it to compile __FILE__ nodes.

Read

Class variables will change their type based on if they are inside of a method definition or not, so we need to track that state.

Read

Some nodes will change their representation if they are inside of a pattern, so we need to track that state.

Class Methods

Initialize a new compiler with the given file name.

Instance Methods

If a class variable is written within a method definition, it has a different type than everywhere else.

Create a new compiler with the given options.

Call nodes with operators following them will either be op_asgn or op_asgn2 nodes. That is determined by their call operator and their right-hand side.

Call nodes with operators following them can use &. as an operator, which changes their type by prefixing “safe_”.

Create a new Sexp object from the given prism node and arguments.

alias $foo $bar ^^^^^^^^^^^^^^^

alias foo bar ^^^^^^^^^^^^^

foo => bar | baz

^^^^^^^^^

a and b ^^^^^^^

foo(bar)

^^^

^^

foo => [bar]

^^^^^

{ a: 1 }

^^^^

def foo(**); bar(**); end

^^

{ **foo }

^^^^^

$+ ^^

begin end ^^^^^^^^^

Visit a block node, which will modify the AST by wrapping the given visited node in an iter node.

foo(&bar)

^^^^

foo { |; bar| }

^^^

A block on a keyword or method call.

def foo(&bar); end

^^^^

A block’s parameters.

break ^^^^^

break foo ^^^^^^^^^

foo.bar &&= baz ^^^^^^^^^^^^^^^

foo ^^^

foo.bar ^^^^^^^

foo.bar() {} ^^^^^^^^^^^^

foo.bar += baz ^^^^^^^^^^^^^^^

foo.bar ||= baz ^^^^^^^^^^^^^^^

foo.bar, = 1 ^^^^^^^

foo => bar => baz

^^^^^^^^^^

case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^

case foo; when bar; end ^^^^^^^^^^^^^^^^^^^^^^^

class Foo; end ^^^^^^^^^^^^^^

@@foo &&= bar ^^^^^^^^^^^^^

@@foo += bar ^^^^^^^^^^^^

@@foo ||= bar ^^^^^^^^^^^^^

@@foo ^^^^^

@@foo, = bar ^^^^^

@@foo = 1 ^^^^^^^^^

@@foo, @@bar = 1 ^^^^^ ^^^^^

Foo &&= bar ^^^^^^^^^^^^

Foo += bar ^^^^^^^^^^^

Foo ||= bar ^^^^^^^^^^^^

Foo::Bar &&= baz ^^^^^^^^^^^^^^^^

Foo::Bar ^^^^^^^^

Foo::Bar += baz ^^^^^^^^^^^^^^^

Foo::Bar ||= baz ^^^^^^^^^^^^^^^^

Foo::Bar, = baz ^^^^^^^^

Foo::Bar = 1 ^^^^^^^^^^^^

Foo::Foo, Bar::Bar = 1 ^^^^^^^^ ^^^^^^^^

Foo ^^^

Foo, = bar ^^^

Foo = 1 ^^^^^^^

Foo, Bar = 1 ^^^ ^^^

def foo; end ^^^^^^^^^^^^

def self.foo; end ^^^^^^^^^^^^^^^^^

defined? a ^^^^^^^^^^

defined?(a) ^^^^^^^^^^^

def foo((bar, baz)); end

^^^^^^^^^^

if foo then bar else baz end

^^^^^^^^^^^^

“foo #{bar}”

^^^^^^

“foo #@bar”

^^^^^

begin; foo; ensure; bar; end

^^^^^^^^^^^^

false ^^^^^

foo => [*, bar, *]

^^^^^^^^^^^

if foo .. bar; end

^^^^^^^^^^

1.0 ^^^

for foo in bar do end ^^^^^^^^^^^^^^^^^^^^^

def foo(…); bar(…); end

^^^

def foo(…); end

^^^

super ^^^^^

super {} ^^^^^^^^

$foo &&= bar ^^^^^^^^^^^^

$foo += bar ^^^^^^^^^^^

$foo ||= bar ^^^^^^^^^^^^

$foo ^^^^

$foo, = bar ^^^^

$foo = 1 ^^^^^^^^

$foo, $bar = 1 ^^^^ ^^^^

{} ^^

foo => {}

^^

if foo then bar end ^^^^^^^^^^^^^^^^^^^

bar if foo ^^^^^^^^^^

foo ? bar : baz ^^^^^^^^^^^^^^^

1i

{ foo: }

^^^^

foo { |bar,| }

^

case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^

foo &&= baz ^^^^^^^^^^^^^^^^

foo += baz ^^^^^^^^^^^^^^^

foo ||= baz ^^^^^^^^^^^^^^^^

foo, = 1 ^^^^^^^^

@foo &&= bar ^^^^^^^^^^^^

@foo += bar ^^^^^^^^^^^

@foo ||= bar ^^^^^^^^^^^^

@foo ^^^^

@foo, = bar ^^^^

@foo = 1 ^^^^^^^^

@foo, @bar = 1 ^^^^ ^^^^

1 ^

if /foo #{bar}/ then end

^^^^^^^^^^^^

Visit the interpolated content of the string-like node.

/foo #{bar}/ ^^^^^^^^^^^^

“foo #{bar}” ^^^^^^^^^^^^

:“foo #{bar}” ^^^^^^^^^^^^^

‘foo #{bar}` ^^^^^^^^^^^^

-> { it }

^^

foo(bar: baz)

^^^^^^^^

def foo(**bar); end

^^^^^

def foo(**); end

^^

-> {}

foo &&= bar ^^^^^^^^^^^

foo += bar ^^^^^^^^^^

foo ||= bar ^^^^^^^^^^^

foo ^^^

foo, = bar ^^^

foo = 1 ^^^^^^^

foo, bar = 1 ^^^ ^^^

if /foo/ then end

^^^^^

foo in bar ^^^^^^^^^^

foo => bar ^^^^^^^^^^

/(?<foo>foo)/ =~ bar ^^^^^^^^^^^^^^^^^^^^

A node that is missing from the syntax tree. This is only used in the case of a syntax error. The parser gem doesn’t have such a concept, so we invent our own here.

module Foo; end ^^^^^^^^^^^^^^^

foo, bar = baz ^^^^^^^^

foo, bar = baz ^^^^^^^^^^^^^^

next ^^^^

next foo ^^^^^^^^

nil ^^^

def foo(**nil); end

^^^^^

-> { _1 + _2 } ^^^^^^^^^^^^^^

$1 ^^

def foo(bar: baz); end

^^^^^^^^

def foo(bar = 1); end

^^^^^^^

a or b ^^^^^^

def foo(bar, *baz); end

^^^^^^^^^

() ^^

(1) ^^^

Pattern constants get wrapped in another layer of :const.

foo => ^(bar)

^^^^^^

foo = 1 and bar => ^foo

^^^^

END {}

BEGIN {}

The top-level program node.

If the bounds of a range node are empty parentheses, then they do not get replaced by their usual s(:nil), but instead are s(:begin).

0..5 ^^^^

1r ^^

redo ^^^^

/foo/ ^^^^^

def foo(bar:); end

^^^^

def foo(bar); end

^^^

foo rescue bar ^^^^^^^^^^^^^^

begin; rescue; end

^^^^^^^

def foo(*bar); end

^^^^

def foo(*); end

^

retry ^^^^^

return ^^^^^^

return 1 ^^^^^^^^

self ^^^^

A shareable constant.

class << self; end ^^^^^^^^^^^^^^^^^^

__ENCODING__ ^^^^^^^^^^^^

__FILE__ ^^^^^^^^

__LINE__ ^^^^^^^^

foo(*bar)

^^^^

def foo((bar, *baz)); end

^^^^

def foo(*); bar(*); end

^

A list of statements.

“foo” ^^^^^

super(foo) ^^^^^^^^^^

:foo ^^^^

true ^^^^

undef foo ^^^^^^^^^

unless foo; bar end ^^^^^^^^^^^^^^^^^^^

bar unless foo ^^^^^^^^^^^^^^

until foo; bar end ^^^^^^^^^^^^^^^^^

bar until foo ^^^^^^^^^^^^^

case foo; when bar; end

^^^^^^^^^^^^^

while foo; bar end ^^^^^^^^^^^^^^^^^^

bar while foo ^^^^^^^^^^^^^

Visit the value of a write, which will be on the right-hand side of a write operator. Because implicit arrays can have splats, those could potentially be wrapped in an svalue node.

‘foo` ^^^^^

yield ^^^^^

yield 1 ^^^^^^^