Class: ASTTransform::ThunkLowering

Inherits:
Object
  • Object
show all
Includes:
TransformationHelper
Defined in:
lib/ast_transform/thunk_lowering.rb

Overview

Lowers Thunk nodes into plain Ruby ahead of emission. Each unique thunk (grouped by id identity) becomes a hidden proc; each occurrence becomes the proc's call:

thunk placed at the execution point
=> x = x; __ast_thunk_<n>__ = proc { body }   (at the body's source lines)
   ...
   __ast_thunk_<n>__.call                     (at the occurrence)

Placement is inferred, not authored: the proc's text is inserted into the statement sequence enclosing the occurrence, positioned among its siblings by the body's first source line — the lines the author removed the statements from. A loc-less body has no textual home and packs immediately before its call. Placements never escape a scope boundary (def/class/module bodies absorb their own), because the hidden lvar must share the call's method activation; they DO escape block literals, which close over the defining scope.

The closure is a non-lambda proc on purpose: return inside a proc returns from the method where the proc was defined, and placement and execution always share one method activation, so a thunked return keeps its original meaning. Jump keywords whose owner lies outside the body keep Ruby's native behavior (break/retry fail loudly, next/redo silently alter flow) — what a transform chooses to thunk is the transform author's call.

The x = x pre-declarations cover every local the body assigns at method scope. A local first assigned inside a block literal is block-local, so without a textual method-scope assignment before the proc, thunked assignments would be invisible to the statements that read them after the execution point. Self-assignment registers the name (nil until the thunk runs — exactly what an unexecuted assignment yields) without clobbering an already-assigned value.

Stateless: the thunks encountered during one lowering are tracked in a Registry created at lower entry, so an instance is a reusable collaborator.

Defined Under Namespace

Classes: Placement, PlacementError

Constant Summary collapse

SEQUENCE_TYPES =
[:begin, :kwbegin].freeze
SCOPE_BODY_INDEXES =

Scope-opening containers: the hidden lvar cannot be referenced across these boundaries, so placements arising inside must land inside.

{ def: 2, defs: 3, class: 2, module: 1, sclass: 1 }.freeze

Instance Method Summary collapse

Methods included from TransformationHelper

included

Instance Method Details

#lower(node) ⇒ Parser::AST::Node

Returns tree with thunks lowered to plain Ruby.

Parameters:

  • node (Parser::AST::Node)

    tree possibly containing Thunk nodes

Returns:

  • (Parser::AST::Node)

    tree with thunks lowered to plain Ruby

Raises:

  • (PlacementError)

    when a thunk body's source lines fall after its execution point, or occurrences of one thunk diverge



93
94
95
# File 'lib/ast_transform/thunk_lowering.rb', line 93

def lower(node)
  lower_body(node, Registry.new)
end