summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <[email protected]>2024-07-02 14:27:04 -0400
committerKevin Newton <[email protected]>2024-07-11 14:25:54 -0400
commitca48fb76fb0669ca0666a7aa129e1f5d2b7468da (patch)
treefce04cbe37f6976af6824f885a6032f66df7d470
parent678dd769e560db9cebff41218e3413e6688aaf12 (diff)
[ruby/prism] Move location to second position for node initializers
https://github.com/ruby/prism/commit/4cc0eda4ca
-rw-r--r--lib/prism/desugar_compiler.rb185
-rw-r--r--lib/prism/node_ext.rb20
-rw-r--r--lib/prism/parse_result.rb13
-rw-r--r--lib/prism/parse_result/errors.rb5
-rw-r--r--prism/templates/ext/prism/api_node.c.erb8
-rw-r--r--prism/templates/lib/prism/dsl.rb.erb115
-rw-r--r--prism/templates/lib/prism/node.rb.erb10
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb12
-rw-r--r--test/prism/errors/content_after_unterminated_heredoc.txt2
-rw-r--r--test/prism/snapshots/patterns.txt144
10 files changed, 363 insertions, 151 deletions
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
index de02445149..c51bdd2b1c 100644
--- a/lib/prism/desugar_compiler.rb
+++ b/lib/prism/desugar_compiler.rb
@@ -2,11 +2,13 @@
module Prism
class DesugarAndWriteNode # :nodoc:
- attr_reader :node, :source, :read_class, :write_class, :arguments
+ include DSL
- def initialize(node, source, read_class, write_class, *arguments)
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
+
+ def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
- @source = source
+ @default_source = default_source
@read_class = read_class
@write_class = write_class
@arguments = arguments
@@ -14,22 +16,30 @@ module Prism
# Desugar `x &&= y` to `x && x = y`
def compile
- AndNode.new(
- source,
- read_class.new(source, *arguments, node.name_loc),
- write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
+ and_node(
+ location: node.location,
+ left: public_send(read_class, location: node.name_loc, **arguments),
+ right: public_send(
+ write_class,
+ location: node.location,
+ **arguments,
+ name_loc: node.name_loc,
+ value: node.value,
+ operator_loc: node.operator_loc
+ ),
+ operator_loc: node.operator_loc
)
end
end
class DesugarOrWriteDefinedNode # :nodoc:
- attr_reader :node, :source, :read_class, :write_class, :arguments
+ include DSL
+
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
- def initialize(node, source, read_class, write_class, *arguments)
+ def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
- @source = source
+ @default_source = default_source
@read_class = read_class
@write_class = write_class
@arguments = arguments
@@ -37,35 +47,50 @@ module Prism
# Desugar `x ||= y` to `defined?(x) ? x : x = y`
def compile
- IfNode.new(
- source,
- node.operator_loc,
- DefinedNode.new(source, nil, read_class.new(source, *arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
- node.operator_loc,
- StatementsNode.new(source, [read_class.new(source, *arguments, node.name_loc)], node.location),
- ElseNode.new(
- source,
- node.operator_loc,
- StatementsNode.new(
- source,
- [write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location)],
- node.location
+ if_node(
+ location: node.location,
+ if_keyword_loc: node.operator_loc,
+ predicate: defined_node(
+ location: node.name_loc,
+ value: public_send(read_class, location: node.name_loc, **arguments),
+ keyword_loc: node.operator_loc
+ ),
+ then_keyword_loc: node.operator_loc,
+ statements: statements_node(
+ location: node.location,
+ body: [public_send(read_class, location: node.name_loc, **arguments)]
+ ),
+ consequent: else_node(
+ location: node.location,
+ else_keyword_loc: node.operator_loc,
+ statements: statements_node(
+ location: node.location,
+ body: [
+ public_send(
+ write_class,
+ location: node.location,
+ **arguments,
+ name_loc: node.name_loc,
+ value: node.value,
+ operator_loc: node.operator_loc
+ )
+ ]
),
- node.operator_loc,
- node.location
+ end_keyword_loc: node.operator_loc
),
- node.operator_loc,
- node.location
+ end_keyword_loc: node.operator_loc
)
end
end
class DesugarOperatorWriteNode # :nodoc:
- attr_reader :node, :source, :read_class, :write_class, :arguments
+ include DSL
- def initialize(node, source, read_class, write_class, *arguments)
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
+
+ def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
- @source = source
+ @default_source = default_source
@read_class = read_class
@write_class = write_class
@arguments = arguments
@@ -75,35 +100,41 @@ module Prism
def compile
binary_operator_loc = node.binary_operator_loc.chop
- write_class.new(
- source,
- *arguments,
- node.name_loc,
- CallNode.new(
- source,
- 0,
- read_class.new(source, *arguments, node.name_loc),
- nil,
- binary_operator_loc.slice.to_sym,
- binary_operator_loc,
- nil,
- ArgumentsNode.new(source, 0, [node.value], node.value.location),
- nil,
- nil,
- node.location
+ public_send(
+ write_class,
+ location: node.location,
+ **arguments,
+ name_loc: node.name_loc,
+ value: call_node(
+ location: node.location,
+ receiver: public_send(
+ read_class,
+ location: node.name_loc,
+ **arguments
+ ),
+ name: binary_operator_loc.slice.to_sym,
+ message_loc: binary_operator_loc,
+ arguments: arguments_node(
+ location: node.value.location,
+ arguments: [node.value]
+ )
),
- node.binary_operator_loc.copy(start_offset: node.binary_operator_loc.end_offset - 1, length: 1),
- node.location
+ operator_loc: node.binary_operator_loc.copy(
+ start_offset: node.binary_operator_loc.end_offset - 1,
+ length: 1
+ )
)
end
end
class DesugarOrWriteNode # :nodoc:
- attr_reader :node, :source, :read_class, :write_class, :arguments
+ include DSL
- def initialize(node, source, read_class, write_class, *arguments)
+ attr_reader :node, :default_source, :read_class, :write_class, :arguments
+
+ def initialize(node, default_source, read_class, write_class, **arguments)
@node = node
- @source = source
+ @default_source = default_source
@read_class = read_class
@write_class = write_class
@arguments = arguments
@@ -111,12 +142,18 @@ module Prism
# Desugar `x ||= y` to `x || x = y`
def compile
- OrNode.new(
- source,
- read_class.new(source, *arguments, node.name_loc),
- write_class.new(source, *arguments, node.name_loc, node.value, node.operator_loc, node.location),
- node.operator_loc,
- node.location
+ or_node(
+ location: node.location,
+ left: public_send(read_class, location: node.name_loc, **arguments),
+ right: public_send(
+ write_class,
+ location: node.location,
+ **arguments,
+ name_loc: node.name_loc,
+ value: node.value,
+ operator_loc: node.operator_loc
+ ),
+ operator_loc: node.operator_loc
)
end
end
@@ -125,91 +162,91 @@ module Prism
class ClassVariableAndWriteNode
def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
+ DesugarAndWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ClassVariableOrWriteNode
def desugar # :nodoc:
- DesugarOrWriteDefinedNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
+ DesugarOrWriteDefinedNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ClassVariableOperatorWriteNode
def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, ClassVariableReadNode, ClassVariableWriteNode, name).compile
+ DesugarOperatorWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
end
end
class ConstantAndWriteNode
def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
+ DesugarAndWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class ConstantOrWriteNode
def desugar # :nodoc:
- DesugarOrWriteDefinedNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
+ DesugarOrWriteDefinedNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class ConstantOperatorWriteNode
def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, ConstantReadNode, ConstantWriteNode, name).compile
+ DesugarOperatorWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
end
end
class GlobalVariableAndWriteNode
def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
+ DesugarAndWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class GlobalVariableOrWriteNode
def desugar # :nodoc:
- DesugarOrWriteDefinedNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
+ DesugarOrWriteDefinedNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class GlobalVariableOperatorWriteNode
def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, GlobalVariableReadNode, GlobalVariableWriteNode, name).compile
+ DesugarOperatorWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
end
end
class InstanceVariableAndWriteNode
def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
+ DesugarAndWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class InstanceVariableOrWriteNode
def desugar # :nodoc:
- DesugarOrWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
+ DesugarOrWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class InstanceVariableOperatorWriteNode
def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, InstanceVariableReadNode, InstanceVariableWriteNode, name).compile
+ DesugarOperatorWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
end
end
class LocalVariableAndWriteNode
def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
+ DesugarAndWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
class LocalVariableOrWriteNode
def desugar # :nodoc:
- DesugarOrWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
+ DesugarOrWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
class LocalVariableOperatorWriteNode
def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, LocalVariableReadNode, LocalVariableWriteNode, name, depth).compile
+ DesugarOperatorWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
end
end
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
index aa6a18cf29..fe36be8541 100644
--- a/lib/prism/node_ext.rb
+++ b/lib/prism/node_ext.rb
@@ -69,11 +69,11 @@ module Prism
def to_interpolated
InterpolatedStringNode.new(
source,
+ location,
frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
opening_loc,
- [copy(opening_loc: nil, closing_loc: nil, location: content_loc)],
- closing_loc,
- location
+ [copy(location: content_loc, opening_loc: nil, closing_loc: nil)],
+ closing_loc
)
end
end
@@ -86,10 +86,10 @@ module Prism
def to_interpolated
InterpolatedXStringNode.new(
source,
+ location,
opening_loc,
- [StringNode.new(source, 0, nil, content_loc, nil, unescaped, content_loc)],
- closing_loc,
- location
+ [StringNode.new(source, content_loc, 0, nil, content_loc, nil, unescaped)],
+ closing_loc
)
end
end
@@ -115,9 +115,9 @@ module Prism
deprecated("value", "numerator", "denominator")
if denominator == 1
- IntegerNode.new(source, flags, numerator, location.chop)
+ IntegerNode.new(source, location.chop, flags, numerator)
else
- FloatNode.new(source, numerator.to_f / denominator, location.chop)
+ FloatNode.new(source, location.chop, numerator.to_f / denominator)
end
end
end
@@ -195,7 +195,7 @@ module Prism
# continue to supply that API.
def child
deprecated("name", "name_loc")
- name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
+ name ? ConstantReadNode.new(source, name_loc, name) : MissingNode.new(source, location)
end
end
@@ -231,7 +231,7 @@ module Prism
# continue to supply that API.
def child
deprecated("name", "name_loc")
- name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
+ name ? ConstantReadNode.new(source, name_loc, name) : MissingNode.new(source, location)
end
end
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb
index cc4f942283..ae57242707 100644
--- a/lib/prism/parse_result.rb
+++ b/lib/prism/parse_result.rb
@@ -10,7 +10,11 @@ module Prism
# specialized and more performant `ASCIISource` if no multibyte characters
# are present in the source code.
def self.for(source, start_line = 1, offsets = [])
- source.ascii_only? ? ASCIISource.new(source, start_line, offsets): new(source, start_line, offsets)
+ if source.ascii_only?
+ ASCIISource.new(source, start_line, offsets)
+ else
+ new(source, start_line, offsets)
+ end
end
# The source code that this source object represents.
@@ -87,7 +91,12 @@ module Prism
# encodings, it is not captured here.
def code_units_offset(byte_offset, encoding)
byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding)
- (encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE) ? (byteslice.bytesize / 2) : byteslice.length
+
+ if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
+ byteslice.bytesize / 2
+ else
+ byteslice.length
+ end
end
# Returns the column number in code units for the given encoding for the
diff --git a/lib/prism/parse_result/errors.rb b/lib/prism/parse_result/errors.rb
index 40dda3c264..1eaeebee6e 100644
--- a/lib/prism/parse_result/errors.rb
+++ b/lib/prism/parse_result/errors.rb
@@ -4,13 +4,18 @@ require "stringio"
module Prism
class ParseResult < Result
+ # An object to represent the set of errors on a parse result. This object
+ # can be used to format the errors in a human-readable way.
class Errors
+ # The parse result that contains the errors.
attr_reader :parse_result
+ # Initialize a new set of errors from the given parse result.
def initialize(parse_result)
@parse_result = parse_result
end
+ # Formats the errors in a human-readable way and return them as a string.
def format
error_lines = {}
parse_result.errors.each do |error|
diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb
index de6f4b95fd..258c61f319 100644
--- a/prism/templates/ext/prism/api_node.c.erb
+++ b/prism/templates/ext/prism/api_node.c.erb
@@ -177,7 +177,10 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
// source
argv[0] = source;
- <%- node.fields.each.with_index(1) do |field, index| -%>
+
+ // location
+ argv[1] = pm_location_new(parser, node->location.start, node->location.end);
+ <%- node.fields.each.with_index(2) do |field, index| -%>
// <%= field.name %>
<%- case field -%>
@@ -232,9 +235,6 @@ pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encodi
<%- end -%>
<%- end -%>
- // location
- argv[<%= node.fields.length + 1 %>] = pm_location_new(parser, node->location.start, node->location.end);
-
rb_ary_push(value_stack, rb_class_new_instance(<%= node.fields.length + 2 %>, argv, rb_cPrism<%= node.name %>));
break;
}
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
index eff0d1c4fc..4f61d71a2a 100644
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ b/prism/templates/lib/prism/dsl.rb.erb
@@ -5,45 +5,118 @@ module Prism
# source = Prism::Source.for("[1]")
#
# Prism::ArrayNode.new(
+ # source,
+ # Prism::Location.new(source, 0, 3),
+ # 0,
# [
# Prism::IntegerNode.new(
- # Prism::IntegerBaseFlags::DECIMAL,
- # 1,
+ # source,
# Prism::Location.new(source, 1, 1),
- # source
+ # Prism::IntegerBaseFlags::DECIMAL,
+ # 1
# )
# ],
# Prism::Location.new(source, 0, 1),
- # Prism::Location.new(source, 2, 1),
- # source
+ # Prism::Location.new(source, 2, 1)
# )
#
# you could instead write:
#
- # source = Prism::Source.for("[1]")
+ # class Builder
+ # include Prism::DSL
#
- # ArrayNode(
- # IntegerNode(Prism::IntegerBaseFlags::DECIMAL, 1, Location(source, 1, 1)), source),
- # Location(source, 0, 1),
- # Location(source, 2, 1),
- # source
- # )
+ # attr_reader :default_source
+ #
+ # def initialize
+ # @default_source = source("[1]")
+ # end
#
- # This is mostly helpful in the context of writing tests, but can also be used
- # to generate trees programmatically.
+ # def build
+ # array_node(
+ # location: location(start_offset: 0, length: 3),
+ # elements: [
+ # integer_node(
+ # location: location(start_offset: 1, length: 1),
+ # flags: integer_base_flag(:decimal),
+ # value: 1
+ # )
+ # ],
+ # opening_loc: location(start_offset: 0, length: 1),
+ # closing_loc: location(start_offset: 2, length: 1)
+ # )
+ # end
+ # end
+ #
+ # This is mostly helpful in the context of generating trees programmatically.
module DSL
- private
+ # Provide all of these methods as module methods as well, to allow for
+ # building nodes like Prism::DSL.nil_node.
+ extend self
- # Create a new Location object
- def Location(source = nil, start_offset = 0, length = 0)
- Location.new(source, start_offset, length) # steep:ignore
+ # Create a new Source object.
+ def source(string)
+ Source.for(string)
+ end
+
+ # Create a new Location object.
+ def location(source: default_source, start_offset: 0, length: 0)
+ Location.new(source, start_offset, length)
end
<%- nodes.each do |node| -%>
- # Create a new <%= node.name %> node
- def <%= node.name %>(<%= (node.fields.map(&:name) + ["source = nil, location = Location()"]).join(", ") %>)
- <%= node.name %>.new(<%= ["source", *node.fields.map(&:name), "location"].join(", ") %>)
+ # Create a new <%= node.name %> node.
+ def <%= node.human %>(<%= ["source: default_source", "location: default_location", *node.fields.map { |field|
+ case field
+ when Prism::Template::NodeField, Prism::Template::ConstantField
+ "#{field.name}: default_node(source, location)"
+ when Prism::Template::OptionalNodeField, Prism::Template::OptionalConstantField, Prism::Template::OptionalLocationField
+ "#{field.name}: nil"
+ when Prism::Template::NodeListField, Prism::Template::ConstantListField
+ "#{field.name}: []"
+ when Prism::Template::StringField
+ "#{field.name}: \"\""
+ when Prism::Template::LocationField
+ "#{field.name}: location"
+ when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::FlagsField, Prism::Template::IntegerField, Prism::Template::DoubleField
+ "#{field.name}: 0"
+ else
+ raise
+ end
+ }].join(", ") %>)
+ <%= node.name %>.new(<%= ["source", "location", *node.fields.map(&:name)].join(", ") %>)
end
<%- end -%>
+ <%- flags.each do |flag| -%>
+
+ # Retrieve the value of one of the <%= flag.name %> flags.
+ def <%= flag.human.chomp("s") %>(name)
+ case name
+ <%- flag.values.each do |value| -%>
+ when :<%= value.name.downcase %> then <%= flag.name %>::<%= value.name %>
+ <%- end -%>
+ else raise ArgumentError, "invalid <%= flag.name %> flag: #{name.inspect}"
+ end
+ end
+ <%- end -%>
+
+ private
+
+ # The default source object that gets attached to nodes and locations if no
+ # source is specified.
+ def default_source
+ Source.for("")
+ end
+
+ # The default location object that gets attached to nodes if no location is
+ # specified, which uses the given source.
+ def default_location
+ Location.new(default_source, 0, 0)
+ end
+
+ # The default node that gets attached to nodes if no node is specified for a
+ # required node field.
+ def default_node(source, location)
+ MissingNode.new(source, location)
+ end
end
end
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
index f0ce226def..945b62fadb 100644
--- a/prism/templates/lib/prism/node.rb.erb
+++ b/prism/templates/lib/prism/node.rb.erb
@@ -166,8 +166,8 @@ module Prism
#<%= line %>
<%- end -%>
class <%= node.name -%> < Node
- # def initialize: (<%= (node.fields.map { |field| "#{field.rbs_class} #{field.name}" } + ["Location location"]).join(", ") %>) -> void
- def initialize(source, <%= (node.fields.map(&:name) + ["location"]).join(", ") %>)
+ # Initialize a new <%= node.name %> node.
+ def initialize(<%= ["source", "location", *node.fields.map(&:name)].join(", ") %>)
@source = source
@location = location
<%- node.fields.each do |field| -%>
@@ -228,9 +228,9 @@ module Prism
}.compact.join(", ") %>] #: Array[Prism::node | Location]
end
- # def copy: (<%= (node.fields.map { |field| "?#{field.name}: #{field.rbs_class}" } + ["?location: Location"]).join(", ") %>) -> <%= node.name %>
- def copy(<%= (node.fields.map(&:name) + ["location"]).map { |field| "#{field}: self.#{field}" }.join(", ") %>)
- <%= node.name %>.new(<%= ["source", *node.fields.map(&:name), "location"].join(", ") %>)
+ # def copy: (<%= (["?location: Location"] + node.fields.map { |field| "?#{field.name}: #{field.rbs_class}" }).join(", ") %>) -> <%= node.name %>
+ def copy(<%= (["location"] + node.fields.map(&:name)).map { |field| "#{field}: self.#{field}" }.join(", ") %>)
+ <%= node.name %>.new(<%= ["source", "location", *node.fields.map(&:name)].join(", ") %>)
end
# def deconstruct: () -> Array[nil | Node]
diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb
index 19116b9e6b..5532a7fd6a 100644
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ b/prism/templates/lib/prism/serialize.rb.erb
@@ -319,7 +319,7 @@ module Prism
end
end
- if RUBY_ENGINE == 'ruby'
+ if RUBY_ENGINE == "ruby"
def load_node
type = io.getbyte
location = load_location
@@ -330,8 +330,7 @@ module Prism
<%- if node.needs_serialized_length? -%>
load_uint32
<%- end -%>
- <%= node.name %>.new(
- source, <%= (node.fields.map { |field|
+ <%= node.name %>.new(<%= ["source", "location", *node.fields.map { |field|
case field
when Prism::Template::NodeField then "load_node"
when Prism::Template::OptionalNodeField then "load_optional_node"
@@ -348,7 +347,7 @@ module Prism
when Prism::Template::DoubleField then "load_double"
else raise
end
- } + ["location"]).join(", ") -%>)
+ }].join(", ") -%>)
<%- end -%>
end
end
@@ -367,8 +366,7 @@ module Prism
<%- if node.needs_serialized_length? -%>
load_uint32
<%- end -%>
- <%= node.name %>.new(
- source, <%= (node.fields.map { |field|
+ <%= node.name %>.new(<%= ["source", "location", *node.fields.map { |field|
case field
when Prism::Template::NodeField then "load_node"
when Prism::Template::OptionalNodeField then "load_optional_node"
@@ -385,7 +383,7 @@ module Prism
when Prism::Template::DoubleField then "load_double"
else raise
end
- } + ["location"]).join(", ") -%>)
+ }].join(", ") -%>)
},
<%- end -%>
]
diff --git a/test/prism/errors/content_after_unterminated_heredoc.txt b/test/prism/errors/content_after_unterminated_heredoc.txt
index 43815cd9d0..c0446a8c39 100644
--- a/test/prism/errors/content_after_unterminated_heredoc.txt
+++ b/test/prism/errors/content_after_unterminated_heredoc.txt
@@ -1,2 +1,4 @@
<<~FOO.foo
^~~ unterminated heredoc; can't find string "FOO" anywhere before EOF
+ ^~~ unterminated heredoc; can't find string "FOO" anywhere before EOF
+
diff --git a/test/prism/snapshots/patterns.txt b/test/prism/snapshots/patterns.txt
index 17aa23b4b9..51026972e1 100644
--- a/test/prism/snapshots/patterns.txt
+++ b/test/prism/snapshots/patterns.txt
@@ -1,8 +1,8 @@
-@ ProgramNode (location: (1,0)-(217,5))
-├── locals: [:bar, :baz, :qux, :b, :a, :foo, :x]
+@ ProgramNode (location: (1,0)-(220,31))
+├── locals: [:bar, :baz, :qux, :b, :a, :foo, :x, :_a]
└── statements:
- @ StatementsNode (location: (1,0)-(217,5))
- └── body: (length: 180)
+ @ StatementsNode (location: (1,0)-(220,31))
+ └── body: (length: 182)
├── @ MatchRequiredNode (location: (1,0)-(1,10))
│ ├── value:
│ │ @ CallNode (location: (1,0)-(1,3))
@@ -4883,27 +4883,115 @@
│ │ └── operator_loc: (212,11)-(212,13) = "in"
│ ├── opening_loc: (212,7)-(212,8) = "{"
│ └── closing_loc: (212,18)-(212,19) = "}"
- └── @ MultiWriteNode (location: (214,0)-(217,5))
- ├── lefts: (length: 2)
- │ ├── @ LocalVariableTargetNode (location: (215,2)-(215,3))
- │ │ ├── name: :a
- │ │ └── depth: 0
- │ └── @ LocalVariableTargetNode (location: (216,2)-(216,3))
- │ ├── name: :b
- │ └── depth: 0
- ├── rest: ∅
- ├── rights: (length: 0)
- ├── lparen_loc: (214,0)-(214,1) = "("
- ├── rparen_loc: (217,0)-(217,1) = ")"
- ├── operator_loc: (217,2)-(217,3) = "="
- └── value:
- @ CallNode (location: (217,4)-(217,5))
- ├── flags: variable_call, ignore_visibility
- ├── receiver: ∅
- ├── call_operator_loc: ∅
- ├── name: :c
- ├── message_loc: (217,4)-(217,5) = "c"
- ├── opening_loc: ∅
- ├── arguments: ∅
- ├── closing_loc: ∅
- └── block: ∅
+ ├── @ MultiWriteNode (location: (214,0)-(217,5))
+ │ ├── lefts: (length: 2)
+ │ │ ├── @ LocalVariableTargetNode (location: (215,2)-(215,3))
+ │ │ │ ├── name: :a
+ │ │ │ └── depth: 0
+ │ │ └── @ LocalVariableTargetNode (location: (216,2)-(216,3))
+ │ │ ├── name: :b
+ │ │ └── depth: 0
+ │ ├── rest: ∅
+ │ ├── rights: (length: 0)
+ │ ├── lparen_loc: (214,0)-(214,1) = "("
+ │ ├── rparen_loc: (217,0)-(217,1) = ")"
+ │ ├── operator_loc: (217,2)-(217,3) = "="
+ │ └── value:
+ │ @ CallNode (location: (217,4)-(217,5))
+ │ ├── flags: variable_call, ignore_visibility
+ │ ├── receiver: ∅
+ │ ├── call_operator_loc: ∅
+ │ ├── name: :c
+ │ ├── message_loc: (217,4)-(217,5) = "c"
+ │ ├── opening_loc: ∅
+ │ ├── arguments: ∅
+ │ ├── closing_loc: ∅
+ │ └── block: ∅
+ ├── @ CaseMatchNode (location: (219,0)-(219,25))
+ │ ├── predicate:
+ │ │ @ ParenthesesNode (location: (219,5)-(219,7))
+ │ │ ├── body: ∅
+ │ │ ├── opening_loc: (219,5)-(219,6) = "("
+ │ │ └── closing_loc: (219,6)-(219,7) = ")"
+ │ ├── conditions: (length: 1)
+ │ │ └── @ InNode (location: (219,9)-(219,20))
+ │ │ ├── pattern:
+ │ │ │ @ ArrayPatternNode (location: (219,12)-(219,20))
+ │ │ │ ├── constant: ∅
+ │ │ │ ├── requireds: (length: 2)
+ │ │ │ │ ├── @ LocalVariableTargetNode (location: (219,13)-(219,15))
+ │ │ │ │ │ ├── name: :_a
+ │ │ │ │ │ └── depth: 0
+ │ │ │ │ └── @ LocalVariableTargetNode (location: (219,17)-(219,19))
+ │ │ │ │ ├── name: :_a
+ │ │ │ │ └── depth: 0
+ │ │ │ ├── rest: ∅
+ │ │ │ ├── posts: (length: 0)
+ │ │ │ ├── opening_loc: (219,12)-(219,13) = "["
+ │ │ │ └── closing_loc: (219,19)-(219,20) = "]"
+ │ │ ├── statements: ∅
+ │ │ ├── in_loc: (219,9)-(219,11) = "in"
+ │ │ └── then_loc: ∅
+ │ ├── consequent: ∅
+ │ ├── case_keyword_loc: (219,0)-(219,4) = "case"
+ │ └── end_keyword_loc: (219,22)-(219,25) = "end"
+ └── @ CaseMatchNode (location: (220,0)-(220,31))
+ ├── predicate:
+ │ @ ParenthesesNode (location: (220,5)-(220,7))
+ │ ├── body: ∅
+ │ ├── opening_loc: (220,5)-(220,6) = "("
+ │ └── closing_loc: (220,6)-(220,7) = ")"
+ ├── conditions: (length: 1)
+ │ └── @ InNode (location: (220,9)-(220,26))
+ │ ├── pattern:
+ │ │ @ ArrayPatternNode (location: (220,12)-(220,26))
+ │ │ ├── constant: ∅
+ │ │ ├── requireds: (length: 2)
+ │ │ │ ├── @ HashPatternNode (location: (220,13)-(220,18))
+ │ │ │ │ ├── constant: ∅
+ │ │ │ │ ├── elements: (length: 1)
+ │ │ │ │ │ └── @ AssocNode (location: (220,14)-(220,17))
+ │ │ │ │ │ ├── key:
+ │ │ │ │ │ │ @ SymbolNode (location: (220,14)-(220,16))
+ │ │ │ │ │ │ ├── flags: forced_us_ascii_encoding
+ │ │ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ │ │ ├── value_loc: (220,14)-(220,15) = "a"
+ │ │ │ │ │ │ ├── closing_loc: (220,15)-(220,16) = ":"
+ │ │ │ │ │ │ └── unescaped: "a"
+ │ │ │ │ │ ├── value:
+ │ │ │ │ │ │ @ IntegerNode (location: (220,16)-(220,17))
+ │ │ │ │ │ │ ├── flags: decimal
+ │ │ │ │ │ │ └── value: 1
+ │ │ │ │ │ └── operator_loc: ∅
+ │ │ │ │ ├── rest: ∅
+ │ │ │ │ ├── opening_loc: (220,13)-(220,14) = "{"
+ │ │ │ │ └── closing_loc: (220,17)-(220,18) = "}"
+ │ │ │ └── @ HashPatternNode (location: (220,20)-(220,25))
+ │ │ │ ├── constant: ∅
+ │ │ │ ├── elements: (length: 1)
+ │ │ │ │ └── @ AssocNode (location: (220,21)-(220,24))
+ │ │ │ │ ├── key:
+ │ │ │ │ │ @ SymbolNode (location: (220,21)-(220,23))
+ │ │ │ │ │ ├── flags: forced_us_ascii_encoding
+ │ │ │ │ │ ├── opening_loc: ∅
+ │ │ │ │ │ ├── value_loc: (220,21)-(220,22) = "a"
+ │ │ │ │ │ ├── closing_loc: (220,22)-(220,23) = ":"
+ │ │ │ │ │ └── unescaped: "a"
+ │ │ │ │ ├── value:
+ │ │ │ │ │ @ IntegerNode (location: (220,23)-(220,24))
+ │ │ │ │ │ ├── flags: decimal
+ │ │ │ │ │ └── value: 2
+ │ │ │ │ └── operator_loc: ∅
+ │ │ │ ├── rest: ∅
+ │ │ │ ├── opening_loc: (220,20)-(220,21) = "{"
+ │ │ │ └── closing_loc: (220,24)-(220,25) = "}"
+ │ │ ├── rest: ∅
+ │ │ ├── posts: (length: 0)
+ │ │ ├── opening_loc: (220,12)-(220,13) = "["
+ │ │ └── closing_loc: (220,25)-(220,26) = "]"
+ │ ├── statements: ∅
+ │ ├── in_loc: (220,9)-(220,11) = "in"
+ │ └── then_loc: ∅
+ ├── consequent: ∅
+ ├── case_keyword_loc: (220,0)-(220,4) = "case"
+ └── end_keyword_loc: (220,28)-(220,31) = "end"