prism 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -1
- data/Makefile +1 -1
- data/config.yml +422 -3
- data/docs/build_system.md +8 -11
- data/docs/relocation.md +34 -0
- data/ext/prism/api_node.c +18 -10
- data/ext/prism/extconf.rb +13 -36
- data/ext/prism/extension.c +68 -0
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +427 -3
- data/include/prism/defines.h +22 -7
- data/include/prism/diagnostic.h +1 -0
- data/include/prism/parser.h +25 -12
- data/include/prism/version.h +2 -2
- data/include/prism.h +47 -0
- data/lib/prism/dot_visitor.rb +10 -0
- data/lib/prism/dsl.rb +4 -4
- data/lib/prism/ffi.rb +49 -2
- data/lib/prism/inspect_visitor.rb +2 -0
- data/lib/prism/node.rb +1839 -96
- data/lib/prism/parse_result/errors.rb +1 -1
- data/lib/prism/parse_result.rb +140 -3
- data/lib/prism/reflection.rb +2 -2
- data/lib/prism/relocation.rb +504 -0
- data/lib/prism/serialize.rb +17 -5
- data/lib/prism/string_query.rb +30 -0
- data/lib/prism/translation/parser/compiler.rb +36 -26
- data/lib/prism/translation/parser.rb +3 -3
- data/lib/prism/translation/ripper.rb +1 -5
- data/lib/prism/translation/ruby_parser.rb +14 -5
- data/lib/prism.rb +6 -4
- data/prism.gemspec +7 -1
- data/rbi/prism/dsl.rbi +4 -4
- data/rbi/prism/node.rbi +5118 -1030
- data/rbi/prism/parse_result.rbi +29 -0
- data/rbi/prism/string_query.rbi +12 -0
- data/rbi/prism.rbi +34 -34
- data/sig/prism/dsl.rbs +2 -2
- data/sig/prism/node.rbs +13 -98
- data/sig/prism/parse_result.rbs +20 -0
- data/sig/prism/relocation.rbs +185 -0
- data/sig/prism/string_query.rbs +11 -0
- data/src/diagnostic.c +3 -1
- data/src/node.c +18 -0
- data/src/prettyprint.c +32 -0
- data/src/prism.c +586 -195
- data/src/regexp.c +7 -3
- data/src/serialize.c +12 -0
- data/src/static_literals.c +1 -1
- data/src/util/pm_char.c +1 -1
- data/src/util/pm_string.c +1 -0
- metadata +9 -3
@@ -188,7 +188,7 @@ module Prism
|
|
188
188
|
rescue_clause.exceptions.any? ? builder.array(nil, visit_all(rescue_clause.exceptions), nil) : nil,
|
189
189
|
token(rescue_clause.operator_loc),
|
190
190
|
visit(rescue_clause.reference),
|
191
|
-
srange_find(find_start_offset, find_end_offset,
|
191
|
+
srange_find(find_start_offset, find_end_offset, ";"),
|
192
192
|
visit(rescue_clause.statements)
|
193
193
|
)
|
194
194
|
end until (rescue_clause = rescue_clause.subsequent).nil?
|
@@ -294,7 +294,7 @@ module Prism
|
|
294
294
|
visit_all(arguments),
|
295
295
|
token(node.closing_loc),
|
296
296
|
),
|
297
|
-
srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset,
|
297
|
+
srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, "="),
|
298
298
|
visit(node.arguments.arguments.last)
|
299
299
|
),
|
300
300
|
block
|
@@ -311,7 +311,7 @@ module Prism
|
|
311
311
|
if name.end_with?("=") && !message_loc.slice.end_with?("=") && node.arguments && block.nil?
|
312
312
|
builder.assign(
|
313
313
|
builder.attr_asgn(visit(node.receiver), call_operator, token(message_loc)),
|
314
|
-
srange_find(message_loc.end_offset, node.arguments.location.start_offset,
|
314
|
+
srange_find(message_loc.end_offset, node.arguments.location.start_offset, "="),
|
315
315
|
visit(node.arguments.arguments.last)
|
316
316
|
)
|
317
317
|
else
|
@@ -733,10 +733,10 @@ module Prism
|
|
733
733
|
visit(node.index),
|
734
734
|
token(node.in_keyword_loc),
|
735
735
|
visit(node.collection),
|
736
|
-
if node.do_keyword_loc
|
737
|
-
token(
|
736
|
+
if (do_keyword_loc = node.do_keyword_loc)
|
737
|
+
token(do_keyword_loc)
|
738
738
|
else
|
739
|
-
srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset,
|
739
|
+
srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, ";")
|
740
740
|
end,
|
741
741
|
visit(node.statements),
|
742
742
|
token(node.end_keyword_loc)
|
@@ -865,10 +865,10 @@ module Prism
|
|
865
865
|
builder.condition(
|
866
866
|
token(node.if_keyword_loc),
|
867
867
|
visit(node.predicate),
|
868
|
-
if node.then_keyword_loc
|
869
|
-
token(
|
868
|
+
if (then_keyword_loc = node.then_keyword_loc)
|
869
|
+
token(then_keyword_loc)
|
870
870
|
else
|
871
|
-
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset,
|
871
|
+
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, ";")
|
872
872
|
end,
|
873
873
|
visit(node.statements),
|
874
874
|
case node.subsequent
|
@@ -931,7 +931,11 @@ module Prism
|
|
931
931
|
token(node.in_loc),
|
932
932
|
pattern,
|
933
933
|
guard,
|
934
|
-
|
934
|
+
if (then_loc = node.then_loc)
|
935
|
+
token(then_loc)
|
936
|
+
else
|
937
|
+
srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, ";")
|
938
|
+
end,
|
935
939
|
visit(node.statements)
|
936
940
|
)
|
937
941
|
end
|
@@ -1781,10 +1785,10 @@ module Prism
|
|
1781
1785
|
builder.condition(
|
1782
1786
|
token(node.keyword_loc),
|
1783
1787
|
visit(node.predicate),
|
1784
|
-
if node.then_keyword_loc
|
1785
|
-
token(
|
1788
|
+
if (then_keyword_loc = node.then_keyword_loc)
|
1789
|
+
token(then_keyword_loc)
|
1786
1790
|
else
|
1787
|
-
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset,
|
1791
|
+
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, ";")
|
1788
1792
|
end,
|
1789
1793
|
visit(node.else_clause),
|
1790
1794
|
token(node.else_clause&.else_keyword_loc),
|
@@ -1812,7 +1816,11 @@ module Prism
|
|
1812
1816
|
:until,
|
1813
1817
|
token(node.keyword_loc),
|
1814
1818
|
visit(node.predicate),
|
1815
|
-
|
1819
|
+
if (do_keyword_loc = node.do_keyword_loc)
|
1820
|
+
token(do_keyword_loc)
|
1821
|
+
else
|
1822
|
+
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
|
1823
|
+
end,
|
1816
1824
|
visit(node.statements),
|
1817
1825
|
token(node.closing_loc)
|
1818
1826
|
)
|
@@ -1832,10 +1840,10 @@ module Prism
|
|
1832
1840
|
builder.when(
|
1833
1841
|
token(node.keyword_loc),
|
1834
1842
|
visit_all(node.conditions),
|
1835
|
-
if node.then_keyword_loc
|
1836
|
-
token(
|
1843
|
+
if (then_keyword_loc = node.then_keyword_loc)
|
1844
|
+
token(then_keyword_loc)
|
1837
1845
|
else
|
1838
|
-
srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset,
|
1846
|
+
srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, ";")
|
1839
1847
|
end,
|
1840
1848
|
visit(node.statements)
|
1841
1849
|
)
|
@@ -1852,7 +1860,11 @@ module Prism
|
|
1852
1860
|
:while,
|
1853
1861
|
token(node.keyword_loc),
|
1854
1862
|
visit(node.predicate),
|
1855
|
-
|
1863
|
+
if (do_keyword_loc = node.do_keyword_loc)
|
1864
|
+
token(do_keyword_loc)
|
1865
|
+
else
|
1866
|
+
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
|
1867
|
+
end,
|
1856
1868
|
visit(node.statements),
|
1857
1869
|
token(node.closing_loc)
|
1858
1870
|
)
|
@@ -1985,18 +1997,16 @@ module Prism
|
|
1985
1997
|
Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])
|
1986
1998
|
end
|
1987
1999
|
|
1988
|
-
# Constructs a new source range by finding the given
|
1989
|
-
# given start offset and end offset. If the needle is not found, it
|
2000
|
+
# Constructs a new source range by finding the given character between
|
2001
|
+
# the given start offset and end offset. If the needle is not found, it
|
1990
2002
|
# returns nil. Importantly it does not search past newlines or comments.
|
1991
2003
|
#
|
1992
2004
|
# Note that end_offset is allowed to be nil, in which case this will
|
1993
2005
|
# search until the end of the string.
|
1994
|
-
def srange_find(start_offset, end_offset,
|
1995
|
-
if (match = source_buffer.source.byteslice(start_offset...end_offset)
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
[token, Range.new(source_buffer, offset_cache[token_offset], offset_cache[token_offset + token.bytesize])]
|
2006
|
+
def srange_find(start_offset, end_offset, character)
|
2007
|
+
if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*#{character}/])
|
2008
|
+
final_offset = start_offset + match.bytesize
|
2009
|
+
[character, Range.new(source_buffer, offset_cache[final_offset - character.bytesize], offset_cache[final_offset])]
|
2000
2010
|
end
|
2001
2011
|
end
|
2002
2012
|
|
@@ -51,7 +51,7 @@ module Prism
|
|
51
51
|
source = source_buffer.source
|
52
52
|
|
53
53
|
offset_cache = build_offset_cache(source)
|
54
|
-
result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version),
|
54
|
+
result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
|
55
55
|
|
56
56
|
build_ast(result.value, offset_cache)
|
57
57
|
ensure
|
@@ -64,7 +64,7 @@ module Prism
|
|
64
64
|
source = source_buffer.source
|
65
65
|
|
66
66
|
offset_cache = build_offset_cache(source)
|
67
|
-
result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version),
|
67
|
+
result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
|
68
68
|
|
69
69
|
[
|
70
70
|
build_ast(result.value, offset_cache),
|
@@ -83,7 +83,7 @@ module Prism
|
|
83
83
|
offset_cache = build_offset_cache(source)
|
84
84
|
result =
|
85
85
|
begin
|
86
|
-
unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version),
|
86
|
+
unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
|
87
87
|
rescue ::Parser::SyntaxError
|
88
88
|
raise if !recover
|
89
89
|
end
|
@@ -3269,11 +3269,7 @@ module Prism
|
|
3269
3269
|
|
3270
3270
|
# Lazily initialize the parse result.
|
3271
3271
|
def result
|
3272
|
-
@result ||=
|
3273
|
-
begin
|
3274
|
-
scopes = RUBY_VERSION >= "3.3.0" ? [] : [[]]
|
3275
|
-
Prism.parse(source, scopes: scopes)
|
3276
|
-
end
|
3272
|
+
@result ||= Prism.parse(source, partial_script: true)
|
3277
3273
|
end
|
3278
3274
|
|
3279
3275
|
##########################################################################
|
@@ -881,6 +881,7 @@ module Prism
|
|
881
881
|
# Visit the interpolated content of the string-like node.
|
882
882
|
private def visit_interpolated_parts(parts)
|
883
883
|
visited = []
|
884
|
+
|
884
885
|
parts.each do |part|
|
885
886
|
result = visit(part)
|
886
887
|
|
@@ -892,6 +893,7 @@ module Prism
|
|
892
893
|
else
|
893
894
|
visited << result
|
894
895
|
end
|
896
|
+
visited << :space
|
895
897
|
elsif result[0] == :dstr
|
896
898
|
if !visited.empty? && part.parts[0].is_a?(StringNode)
|
897
899
|
# If we are in the middle of an implicitly concatenated string,
|
@@ -907,8 +909,9 @@ module Prism
|
|
907
909
|
end
|
908
910
|
|
909
911
|
state = :beginning #: :beginning | :string_content | :interpolated_content
|
912
|
+
results = []
|
910
913
|
|
911
|
-
visited.
|
914
|
+
visited.each_with_index do |result, index|
|
912
915
|
case state
|
913
916
|
when :beginning
|
914
917
|
if result.is_a?(String)
|
@@ -923,7 +926,9 @@ module Prism
|
|
923
926
|
state = :interpolated_content
|
924
927
|
end
|
925
928
|
when :string_content
|
926
|
-
if result
|
929
|
+
if result == :space
|
930
|
+
# continue
|
931
|
+
elsif result.is_a?(String)
|
927
932
|
results[0] << result
|
928
933
|
elsif result.is_a?(Array) && result[0] == :str
|
929
934
|
results[0] << result[1]
|
@@ -932,7 +937,9 @@ module Prism
|
|
932
937
|
state = :interpolated_content
|
933
938
|
end
|
934
939
|
when :interpolated_content
|
935
|
-
if result
|
940
|
+
if result == :space
|
941
|
+
# continue
|
942
|
+
elsif visited[index - 1] != :space && result.is_a?(Array) && result[0] == :str && results[-1][0] == :str && (results[-1].line_max == result.line)
|
936
943
|
results[-1][1] << result[1]
|
937
944
|
results[-1].line_max = result.line_max
|
938
945
|
else
|
@@ -940,6 +947,8 @@ module Prism
|
|
940
947
|
end
|
941
948
|
end
|
942
949
|
end
|
950
|
+
|
951
|
+
results
|
943
952
|
end
|
944
953
|
|
945
954
|
# -> { it }
|
@@ -1596,13 +1605,13 @@ module Prism
|
|
1596
1605
|
# Parse the given source and translate it into the seattlerb/ruby_parser
|
1597
1606
|
# gem's Sexp format.
|
1598
1607
|
def parse(source, filepath = "(string)")
|
1599
|
-
translate(Prism.parse(source, filepath: filepath,
|
1608
|
+
translate(Prism.parse(source, filepath: filepath, partial_script: true), filepath)
|
1600
1609
|
end
|
1601
1610
|
|
1602
1611
|
# Parse the given file and translate it into the seattlerb/ruby_parser
|
1603
1612
|
# gem's Sexp format.
|
1604
1613
|
def parse_file(filepath)
|
1605
|
-
translate(Prism.parse_file(filepath,
|
1614
|
+
translate(Prism.parse_file(filepath, partial_script: true), filepath)
|
1606
1615
|
end
|
1607
1616
|
|
1608
1617
|
class << self
|
data/lib/prism.rb
CHANGED
@@ -24,7 +24,9 @@ module Prism
|
|
24
24
|
autoload :Pack, "prism/pack"
|
25
25
|
autoload :Pattern, "prism/pattern"
|
26
26
|
autoload :Reflection, "prism/reflection"
|
27
|
+
autoload :Relocation, "prism/relocation"
|
27
28
|
autoload :Serialize, "prism/serialize"
|
29
|
+
autoload :StringQuery, "prism/string_query"
|
28
30
|
autoload :Translation, "prism/translation"
|
29
31
|
autoload :Visitor, "prism/visitor"
|
30
32
|
|
@@ -75,13 +77,13 @@ require_relative "prism/parse_result"
|
|
75
77
|
# it's going to require the built library. Otherwise, it's going to require a
|
76
78
|
# module that uses FFI to call into the library.
|
77
79
|
if RUBY_ENGINE == "ruby" and !ENV["PRISM_FFI_BACKEND"]
|
78
|
-
require "prism/prism"
|
79
|
-
|
80
80
|
# The C extension is the default backend on CRuby.
|
81
81
|
Prism::BACKEND = :CEXT
|
82
|
-
else
|
83
|
-
require_relative "prism/ffi"
|
84
82
|
|
83
|
+
require "prism/prism"
|
84
|
+
else
|
85
85
|
# The FFI backend is used on other Ruby implementations.
|
86
86
|
Prism::BACKEND = :FFI
|
87
|
+
|
88
|
+
require_relative "prism/ffi"
|
87
89
|
end
|
data/prism.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "prism"
|
5
|
-
spec.version = "1.
|
5
|
+
spec.version = "1.3.0"
|
6
6
|
spec.authors = ["Shopify"]
|
7
7
|
spec.email = ["ruby@shopify.com"]
|
8
8
|
|
@@ -35,6 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
"docs/parser_translation.md",
|
36
36
|
"docs/parsing_rules.md",
|
37
37
|
"docs/releasing.md",
|
38
|
+
"docs/relocation.md",
|
38
39
|
"docs/ripper_translation.md",
|
39
40
|
"docs/ruby_api.md",
|
40
41
|
"docs/ruby_parser_translation.md",
|
@@ -88,7 +89,9 @@ Gem::Specification.new do |spec|
|
|
88
89
|
"lib/prism/polyfill/byteindex.rb",
|
89
90
|
"lib/prism/polyfill/unpack1.rb",
|
90
91
|
"lib/prism/reflection.rb",
|
92
|
+
"lib/prism/relocation.rb",
|
91
93
|
"lib/prism/serialize.rb",
|
94
|
+
"lib/prism/string_query.rb",
|
92
95
|
"lib/prism/translation.rb",
|
93
96
|
"lib/prism/translation/parser.rb",
|
94
97
|
"lib/prism/translation/parser33.rb",
|
@@ -109,6 +112,7 @@ Gem::Specification.new do |spec|
|
|
109
112
|
"rbi/prism/node.rbi",
|
110
113
|
"rbi/prism/parse_result.rbi",
|
111
114
|
"rbi/prism/reflection.rbi",
|
115
|
+
"rbi/prism/string_query.rbi",
|
112
116
|
"rbi/prism/translation/parser.rbi",
|
113
117
|
"rbi/prism/translation/parser33.rbi",
|
114
118
|
"rbi/prism/translation/parser34.rbi",
|
@@ -128,7 +132,9 @@ Gem::Specification.new do |spec|
|
|
128
132
|
"sig/prism/parse_result.rbs",
|
129
133
|
"sig/prism/pattern.rbs",
|
130
134
|
"sig/prism/reflection.rbs",
|
135
|
+
"sig/prism/relocation.rbs",
|
131
136
|
"sig/prism/serialize.rbs",
|
137
|
+
"sig/prism/string_query.rbs",
|
132
138
|
"sig/prism/visitor.rbs",
|
133
139
|
"src/diagnostic.c",
|
134
140
|
"src/encoding.c",
|
data/rbi/prism/dsl.rbi
CHANGED
@@ -451,14 +451,14 @@ module Prism::DSL
|
|
451
451
|
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, keyword_loc: Prism::Location, predicate: Prism::Node, then_keyword_loc: T.nilable(Prism::Location), statements: T.nilable(Prism::StatementsNode), else_clause: T.nilable(Prism::ElseNode), end_keyword_loc: T.nilable(Prism::Location)).returns(Prism::UnlessNode) }
|
452
452
|
def unless_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, predicate: default_node(source, location), then_keyword_loc: nil, statements: nil, else_clause: nil, end_keyword_loc: nil); end
|
453
453
|
|
454
|
-
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, keyword_loc: Prism::Location, closing_loc: T.nilable(Prism::Location), predicate: Prism::Node, statements: T.nilable(Prism::StatementsNode)).returns(Prism::UntilNode) }
|
455
|
-
def until_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, closing_loc: nil, predicate: default_node(source, location), statements: nil); end
|
454
|
+
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, keyword_loc: Prism::Location, do_keyword_loc: T.nilable(Prism::Location), closing_loc: T.nilable(Prism::Location), predicate: Prism::Node, statements: T.nilable(Prism::StatementsNode)).returns(Prism::UntilNode) }
|
455
|
+
def until_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, do_keyword_loc: nil, closing_loc: nil, predicate: default_node(source, location), statements: nil); end
|
456
456
|
|
457
457
|
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, keyword_loc: Prism::Location, conditions: T::Array[Prism::Node], then_keyword_loc: T.nilable(Prism::Location), statements: T.nilable(Prism::StatementsNode)).returns(Prism::WhenNode) }
|
458
458
|
def when_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, conditions: [], then_keyword_loc: nil, statements: nil); end
|
459
459
|
|
460
|
-
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, keyword_loc: Prism::Location, closing_loc: T.nilable(Prism::Location), predicate: Prism::Node, statements: T.nilable(Prism::StatementsNode)).returns(Prism::WhileNode) }
|
461
|
-
def while_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, closing_loc: nil, predicate: default_node(source, location), statements: nil); end
|
460
|
+
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, keyword_loc: Prism::Location, do_keyword_loc: T.nilable(Prism::Location), closing_loc: T.nilable(Prism::Location), predicate: Prism::Node, statements: T.nilable(Prism::StatementsNode)).returns(Prism::WhileNode) }
|
461
|
+
def while_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, do_keyword_loc: nil, closing_loc: nil, predicate: default_node(source, location), statements: nil); end
|
462
462
|
|
463
463
|
sig { params(source: Prism::Source, node_id: Integer, location: Prism::Location, flags: Integer, opening_loc: Prism::Location, content_loc: Prism::Location, closing_loc: Prism::Location, unescaped: String).returns(Prism::XStringNode) }
|
464
464
|
def x_string_node(source: default_source, node_id: 0, location: default_location, flags: 0, opening_loc: location, content_loc: location, closing_loc: location, unescaped: ""); end
|