Module: Ryac::LazyRegions
- Defined in:
- lib/ryac/analysis/lazy_regions.rb,
sig/ryac/analysis/lazy_regions.rbs
Overview
A file the program loads at runtime through a dynamic require
(optcarrot's require_relative "driver/#{name}_#{type}") is bundled by
the Concatenator as a registration:
RYAC_LAZY["optcarrot/driver/sdl2_video"] = -> { <the file> }
The lambda is the file's schedule and nothing more: its body runs when
the original require would have, so a require "ffi" or ffi_lib "SDL2" at the file's top level keeps its optional-dependency timing.
For analysis the body is ordinary code in the closed world — one rename
table across the core and the files that subclass it.
Two things about a region are special. TypeProf does not register a class defined inside a block, so it is handed a view of the source with the wrapper bytes blanked (typeprof_view): every byte of the body keeps its position, and the body reads as the top-level code it becomes when it runs. And a region does not exist at boot: a constant it alone defines cannot be aliased at the end of the file, and an external constant it references cannot be hoisted into the preamble.
Regions are recognized by shape — a top-level Const["key"] = -> { ... }
statement with a parameterless lambda — not by the registry's name,
which the aliaser renames like any other constant. Reading a program's
own statement of that shape as a region is safe: every consequence keeps
more names, never fewer.
Class Method Summary collapse
- .blank(bytes, from, to) ⇒ Object
-
.collect(prism_root) ⇒ Object
The lambdas of every registration, in source order.
- .contains?(lambdas, node) ⇒ Boolean
- .each_registration(prism_root) ⇒ Object
- .registration_lambda(statement) ⇒ Object
-
.typeprof_view(content, prism_root) ⇒ Object
The source as TypeProf must read it: each registration's wrapper —
["key"] = -> {` after the registry constant, and the closing `}— replaced by spaces, newlines kept, so the body sits at top level at its original byte positions.
Instance Method Summary collapse
- #self?.blank ⇒ void
- #self?.collect ⇒ Array[Prism::LambdaNode]
- #self?.contains? ⇒ Boolean
- #self?.each_registration {|arg0, arg1| ... } ⇒ void
- #self?.registration_lambda ⇒ Prism::LambdaNode?
- #self?.typeprof_view ⇒ String
Class Method Details
.blank(bytes, from, to) ⇒ Object
83 84 85 |
# File 'lib/ryac/analysis/lazy_regions.rb', line 83 def blank(bytes, from, to) (from...to).each { |i| bytes.setbyte(i, 0x20) unless bytes.getbyte(i) == 0x0a } end |
.collect(prism_root) ⇒ Object
The lambdas of every registration, in source order.
33 34 35 36 37 |
# File 'lib/ryac/analysis/lazy_regions.rb', line 33 def collect(prism_root) lambdas = [] #: Array[Prism::LambdaNode] each_registration(prism_root) { |_statement, lambda_node| lambdas << lambda_node } lambdas end |
.contains?(lambdas, node) ⇒ Boolean
39 40 41 42 |
# File 'lib/ryac/analysis/lazy_regions.rb', line 39 def contains?(lambdas, node) offset = node.location.start_offset lambdas.any? { |lam| offset > lam.opening_loc.start_offset && offset < lam.closing_loc.start_offset } end |
.each_registration(prism_root) ⇒ Object
62 63 64 65 66 67 |
# File 'lib/ryac/analysis/lazy_regions.rb', line 62 def each_registration(prism_root) prism_root.statements.body.each do |statement| lambda_node = registration_lambda(statement) yield statement, lambda_node if lambda_node end end |
.registration_lambda(statement) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/ryac/analysis/lazy_regions.rb', line 69 def registration_lambda(statement) return nil unless statement.is_a?(Prism::CallNode) && statement.name == :[]= return nil unless statement.receiver.is_a?(Prism::ConstantReadNode) args = statement.arguments&.arguments return nil unless args && args.size == 2 key, value = args return nil unless key.is_a?(Prism::StringNode) && value.is_a?(Prism::LambdaNode) return nil if value.parameters value end |
.typeprof_view(content, prism_root) ⇒ Object
The source as TypeProf must read it: each registration's wrapper —
["key"] = -> {` after the registry constant, and the closing `} —
replaced by spaces, newlines kept, so the body sits at top level at
its original byte positions. The registry constant stays, as its own
statement: it is a reference the aliaser renames like any other, and
it has to be renamed at the registration too.
50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/ryac/analysis/lazy_regions.rb', line 50 def typeprof_view(content, prism_root) bytes = content.b each_registration(prism_root) do |statement, lambda_node| # statement.receiver is the registry constant (registration_lambda) from = statement.receiver.location.end_offset # steep:ignore NoMethod blank(bytes, from, lambda_node.opening_loc.end_offset) bytes.setbyte(from, 0x3b) blank(bytes, lambda_node.closing_loc.start_offset, lambda_node.closing_loc.end_offset) end bytes.force_encoding(content.encoding) end |
Instance Method Details
#self?.blank ⇒ void
This method returns an undefined value.
8 |
# File 'sig/ryac/analysis/lazy_regions.rbs', line 8
def self?.blank: (String bytes, Integer from, Integer to) -> void
|
#self?.collect ⇒ Array[Prism::LambdaNode]
3 |
# File 'sig/ryac/analysis/lazy_regions.rbs', line 3
def self?.collect: (Prism::ProgramNode prism_root) -> Array[Prism::LambdaNode]
|
#self?.contains? ⇒ Boolean
4 |
# File 'sig/ryac/analysis/lazy_regions.rbs', line 4
def self?.contains?: (Array[Prism::LambdaNode] lambdas, Prism::Node node) -> bool
|
#self?.each_registration {|arg0, arg1| ... } ⇒ void
This method returns an undefined value.
6 |
# File 'sig/ryac/analysis/lazy_regions.rbs', line 6
def self?.each_registration: (Prism::ProgramNode prism_root) { (Prism::Node, Prism::LambdaNode) -> void } -> void
|
#self?.registration_lambda ⇒ Prism::LambdaNode?
7 |
# File 'sig/ryac/analysis/lazy_regions.rbs', line 7
def self?.registration_lambda: (Prism::Node statement) -> Prism::LambdaNode?
|
#self?.typeprof_view ⇒ String
5 |
# File 'sig/ryac/analysis/lazy_regions.rbs', line 5
def self?.typeprof_view: (String content, Prism::ProgramNode prism_root) -> String
|