A visitor that knows how to convert a prism syntax tree into the whitequark/parser gem’s syntax tree.

Constants

Locations in the parser gem AST are generated using this class. We store a reference to its constant to make it slightly faster to look up.

Attributes
Read

The Parser::Base instance that is being used to build the AST.

Read

The Parser::Builders::Default instance that is being used to build the AST.

The Parser::Source::Buffer instance that is holding a reference to the source code.

The offset cache that is used to map between byte and character offsets in the file.

Read

The types of values that can be forwarded in the current scope.

Whether or not the current node is in a destructure.

Read

Whether or not the current node is in a pattern.

Class Methods

Initialize a new compiler with the given parser, offset cache, and options.

Instance Methods

Initialize a new compiler with the given option overrides, used to visit a subtree with the given options.

When *, **, &, or … are used as an argument in a method call, we check if they were allowed by the current context. To determine that we build this lookup table.

Because we have mutated the AST to allow for newlines in the middle of a rational, we need to manually handle the value here.

Negate the value of a numeric node. This is a special case where you have a negative sign on one line and then a number on the next line. In normal Ruby, this will always be a method call. The parser gem, however, marks this as a numeric literal. We have to massage the tree here to get it into the correct form.

Blocks can have a special set of parameters that automatically expand when given arrays if they have a single required parameter and no other parameters.

Because we have mutated the AST to allow for newlines in the middle of a rational, we need to manually handle the value here.

Constructs a new source range from the given start and end offsets.

Constructs a new source range by finding the given tokens between the given start offset and end offset. If the needle is not found, it returns nil. Importantly it does not search past newlines or comments.

Note that end_offset is allowed to be nil, in which case this will search until the end of the string.

Constructs a new source range from the given start and end offsets.

Transform a location into a token that the parser gem expects.

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 on a call.

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 ^^^^^^^^^^^^

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) ^^^^^^^^^^^

if foo then bar else baz end

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

“foo #{bar}”

^^^^^^

“foo #@bar”

^^^^^

begin; foo; ensure; bar; end

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

false ^^^^^

foo => [*, bar, *]

^^^^^^^^^^^
An alias for visit_range_node

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 => {}

^^

Visit a heredoc that can be either a string or an xstring.

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 ^^^^^^^^

1 ^

/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 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 ^^

Visit a numeric node and account for the optional sign.

def foo(bar: baz); end

^^^^^^^^

def foo(bar = 1); end

^^^^^^^

a or b ^^^^^^

def foo(bar, *baz); end

^^^^^^^^^

() ^^

(1) ^^^

foo => ^(bar)

^^^^^^

foo = 1 and bar => ^foo

^^^^

END {}

BEGIN {}

The top-level program node.

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 ^^^^^^^^^^^^^

‘foo` ^^^^^

yield ^^^^^

yield 1 ^^^^^^^

Within the given block, track that we’re within a pattern.