prism 0.15.1 → 0.17.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 +35 -1
- data/Makefile +12 -0
- data/README.md +3 -1
- data/config.yml +66 -50
- data/docs/configuration.md +2 -0
- data/docs/fuzzing.md +1 -1
- data/docs/javascript.md +90 -0
- data/docs/releasing.md +27 -0
- data/docs/ruby_api.md +2 -0
- data/docs/serialization.md +28 -29
- data/ext/prism/api_node.c +856 -826
- data/ext/prism/api_pack.c +20 -9
- data/ext/prism/extension.c +494 -119
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +3157 -747
- data/include/prism/defines.h +40 -8
- data/include/prism/diagnostic.h +36 -3
- data/include/prism/enc/pm_encoding.h +119 -28
- data/include/prism/node.h +38 -30
- data/include/prism/options.h +204 -0
- data/include/prism/pack.h +44 -33
- data/include/prism/parser.h +445 -199
- data/include/prism/prettyprint.h +26 -0
- data/include/prism/regexp.h +16 -2
- data/include/prism/util/pm_buffer.h +102 -18
- data/include/prism/util/pm_char.h +162 -48
- data/include/prism/util/pm_constant_pool.h +128 -34
- data/include/prism/util/pm_list.h +68 -38
- data/include/prism/util/pm_memchr.h +18 -3
- data/include/prism/util/pm_newline_list.h +71 -28
- data/include/prism/util/pm_state_stack.h +25 -7
- data/include/prism/util/pm_string.h +115 -27
- data/include/prism/util/pm_string_list.h +25 -6
- data/include/prism/util/pm_strncasecmp.h +32 -0
- data/include/prism/util/pm_strpbrk.h +31 -17
- data/include/prism/version.h +28 -3
- data/include/prism.h +229 -36
- data/lib/prism/compiler.rb +5 -5
- data/lib/prism/debug.rb +43 -13
- data/lib/prism/desugar_compiler.rb +1 -1
- data/lib/prism/dispatcher.rb +27 -26
- data/lib/prism/dsl.rb +16 -16
- data/lib/prism/ffi.rb +138 -61
- data/lib/prism/lex_compat.rb +26 -16
- data/lib/prism/mutation_compiler.rb +11 -11
- data/lib/prism/node.rb +426 -227
- data/lib/prism/node_ext.rb +23 -16
- data/lib/prism/node_inspector.rb +1 -1
- data/lib/prism/pack.rb +79 -40
- data/lib/prism/parse_result/comments.rb +7 -2
- data/lib/prism/parse_result/newlines.rb +4 -0
- data/lib/prism/parse_result.rb +157 -21
- data/lib/prism/pattern.rb +14 -3
- data/lib/prism/ripper_compat.rb +28 -10
- data/lib/prism/serialize.rb +935 -307
- data/lib/prism/visitor.rb +9 -5
- data/lib/prism.rb +20 -2
- data/prism.gemspec +11 -2
- data/rbi/prism.rbi +7305 -0
- data/rbi/prism_static.rbi +196 -0
- data/sig/prism.rbs +4468 -0
- data/sig/prism_static.rbs +123 -0
- data/src/diagnostic.c +56 -53
- data/src/enc/pm_big5.c +1 -0
- data/src/enc/pm_euc_jp.c +1 -0
- data/src/enc/pm_gbk.c +1 -0
- data/src/enc/pm_shift_jis.c +1 -0
- data/src/enc/pm_tables.c +316 -80
- data/src/enc/pm_unicode.c +54 -9
- data/src/enc/pm_windows_31j.c +1 -0
- data/src/node.c +357 -345
- data/src/options.c +170 -0
- data/src/prettyprint.c +7697 -1643
- data/src/prism.c +1964 -1125
- data/src/regexp.c +153 -95
- data/src/serialize.c +432 -397
- data/src/token_type.c +3 -1
- data/src/util/pm_buffer.c +88 -23
- data/src/util/pm_char.c +103 -57
- data/src/util/pm_constant_pool.c +52 -22
- data/src/util/pm_list.c +12 -4
- data/src/util/pm_memchr.c +5 -3
- data/src/util/pm_newline_list.c +25 -63
- data/src/util/pm_state_stack.c +9 -3
- data/src/util/pm_string.c +95 -85
- data/src/util/pm_string_list.c +14 -15
- data/src/util/pm_strncasecmp.c +10 -3
- data/src/util/pm_strpbrk.c +25 -19
- metadata +12 -3
- data/docs/prism.png +0 -0
data/lib/prism/compiler.rb
CHANGED
@@ -291,9 +291,6 @@ module Prism
|
|
291
291
|
# Compile a KeywordHashNode node
|
292
292
|
alias visit_keyword_hash_node visit_child_nodes
|
293
293
|
|
294
|
-
# Compile a KeywordParameterNode node
|
295
|
-
alias visit_keyword_parameter_node visit_child_nodes
|
296
|
-
|
297
294
|
# Compile a KeywordRestParameterNode node
|
298
295
|
alias visit_keyword_rest_parameter_node visit_child_nodes
|
299
296
|
|
@@ -354,6 +351,9 @@ module Prism
|
|
354
351
|
# Compile a NumberedReferenceReadNode node
|
355
352
|
alias visit_numbered_reference_read_node visit_child_nodes
|
356
353
|
|
354
|
+
# Compile a OptionalKeywordParameterNode node
|
355
|
+
alias visit_optional_keyword_parameter_node visit_child_nodes
|
356
|
+
|
357
357
|
# Compile a OptionalParameterNode node
|
358
358
|
alias visit_optional_parameter_node visit_child_nodes
|
359
359
|
|
@@ -393,8 +393,8 @@ module Prism
|
|
393
393
|
# Compile a RegularExpressionNode node
|
394
394
|
alias visit_regular_expression_node visit_child_nodes
|
395
395
|
|
396
|
-
# Compile a
|
397
|
-
alias
|
396
|
+
# Compile a RequiredKeywordParameterNode node
|
397
|
+
alias visit_required_keyword_parameter_node visit_child_nodes
|
398
398
|
|
399
399
|
# Compile a RequiredParameterNode node
|
400
400
|
alias visit_required_parameter_node visit_child_nodes
|
data/lib/prism/debug.rb
CHANGED
@@ -4,7 +4,9 @@ module Prism
|
|
4
4
|
# This module is used for testing and debugging and is not meant to be used by
|
5
5
|
# consumers of this library.
|
6
6
|
module Debug
|
7
|
-
|
7
|
+
# A wrapper around a RubyVM::InstructionSequence that provides a more
|
8
|
+
# convenient interface for accessing parts of the iseq.
|
9
|
+
class ISeq # :nodoc:
|
8
10
|
attr_reader :parts
|
9
11
|
|
10
12
|
def initialize(parts)
|
@@ -42,6 +44,11 @@ module Prism
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
47
|
+
private_constant :ISeq
|
48
|
+
|
49
|
+
# :call-seq:
|
50
|
+
# Debug::cruby_locals(source) -> Array
|
51
|
+
#
|
45
52
|
# For the given source, compiles with CRuby and returns a list of all of the
|
46
53
|
# sets of local variables that were encountered.
|
47
54
|
def self.cruby_locals(source)
|
@@ -52,9 +59,21 @@ module Prism
|
|
52
59
|
stack = [ISeq.new(RubyVM::InstructionSequence.compile(source).to_a)]
|
53
60
|
|
54
61
|
while (iseq = stack.pop)
|
55
|
-
|
56
|
-
|
57
|
-
|
62
|
+
names = [*iseq.local_table]
|
63
|
+
names.map!.with_index do |name, index|
|
64
|
+
# When an anonymous local variable is present in the iseq's local
|
65
|
+
# table, it is represented as the stack offset from the top.
|
66
|
+
# However, when these are dumped to binary and read back in, they
|
67
|
+
# are replaced with the symbol :#arg_rest. To consistently handle
|
68
|
+
# this, we replace them here with their index.
|
69
|
+
if name == :"#arg_rest"
|
70
|
+
names.length - index + 1
|
71
|
+
else
|
72
|
+
name
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
locals << names
|
58
77
|
iseq.each_child { |child| stack << child }
|
59
78
|
end
|
60
79
|
|
@@ -64,8 +83,16 @@ module Prism
|
|
64
83
|
end
|
65
84
|
end
|
66
85
|
|
86
|
+
# Used to hold the place of a local that will be in the local table but
|
87
|
+
# cannot be accessed directly from the source code. For example, the
|
88
|
+
# iteration variable in a for loop or the positional parameter on a method
|
89
|
+
# definition that is destructured.
|
67
90
|
AnonymousLocal = Object.new
|
91
|
+
private_constant :AnonymousLocal
|
68
92
|
|
93
|
+
# :call-seq:
|
94
|
+
# Debug::prism_locals(source) -> Array
|
95
|
+
#
|
69
96
|
# For the given source, parses with prism and returns a list of all of the
|
70
97
|
# sets of local variables that were encountered.
|
71
98
|
def self.prism_locals(source)
|
@@ -102,19 +129,21 @@ module Prism
|
|
102
129
|
AnonymousLocal
|
103
130
|
end
|
104
131
|
end,
|
105
|
-
*params.keywords.
|
106
|
-
*params.keywords.
|
132
|
+
*params.keywords.grep(RequiredKeywordParameterNode).map(&:name),
|
133
|
+
*params.keywords.grep(OptionalKeywordParameterNode).map(&:name),
|
107
134
|
]
|
108
135
|
|
109
136
|
sorted << AnonymousLocal if params.keywords.any?
|
110
137
|
|
111
138
|
# Recurse down the parameter tree to find any destructured
|
112
139
|
# parameters and add them after the other parameters.
|
113
|
-
param_stack = params.requireds.concat(params.posts).grep(
|
140
|
+
param_stack = params.requireds.concat(params.posts).grep(MultiTargetNode).reverse
|
114
141
|
while (param = param_stack.pop)
|
115
142
|
case param
|
116
|
-
when
|
117
|
-
param_stack.concat(param.
|
143
|
+
when MultiTargetNode
|
144
|
+
param_stack.concat(param.rights.reverse)
|
145
|
+
param_stack << param.rest
|
146
|
+
param_stack.concat(param.lefts.reverse)
|
118
147
|
when RequiredParameterNode
|
119
148
|
sorted << param.name
|
120
149
|
when SplatNode
|
@@ -150,12 +179,13 @@ module Prism
|
|
150
179
|
locals
|
151
180
|
end
|
152
181
|
|
182
|
+
# :call-seq:
|
183
|
+
# Debug::newlines(source) -> Array
|
184
|
+
#
|
185
|
+
# For the given source string, return the byte offsets of every newline in
|
186
|
+
# the source.
|
153
187
|
def self.newlines(source)
|
154
188
|
Prism.parse(source).source.offsets
|
155
189
|
end
|
156
|
-
|
157
|
-
def self.parse_serialize_file(filepath)
|
158
|
-
parse_serialize_file_metadata(filepath, [filepath.bytesize, filepath.b, 0].pack("LA*L"))
|
159
|
-
end
|
160
190
|
end
|
161
191
|
end
|
data/lib/prism/dispatcher.rb
CHANGED
@@ -41,23 +41,24 @@ module Prism
|
|
41
41
|
# attr_reader listeners: Hash[Symbol, Array[Listener]]
|
42
42
|
attr_reader :listeners
|
43
43
|
|
44
|
+
# Initialize a new dispatcher.
|
44
45
|
def initialize
|
45
46
|
@listeners = {}
|
46
47
|
end
|
47
48
|
|
48
|
-
# Register a listener for one or more events
|
49
|
+
# Register a listener for one or more events.
|
49
50
|
#
|
50
51
|
# def register: (Listener, *Symbol) -> void
|
51
52
|
def register(listener, *events)
|
52
53
|
events.each { |event| (listeners[event] ||= []) << listener }
|
53
54
|
end
|
54
55
|
|
55
|
-
# Walks `root` dispatching events to all registered listeners
|
56
|
+
# Walks `root` dispatching events to all registered listeners.
|
56
57
|
#
|
57
58
|
# def dispatch: (Node) -> void
|
58
59
|
alias dispatch visit
|
59
60
|
|
60
|
-
# Dispatches a single event for `node` to all registered listeners
|
61
|
+
# Dispatches a single event for `node` to all registered listeners.
|
61
62
|
#
|
62
63
|
# def dispatch_once: (Node) -> void
|
63
64
|
def dispatch_once(node)
|
@@ -736,14 +737,6 @@ module Prism
|
|
736
737
|
listeners[:on_keyword_hash_node_leave]&.each { |listener| listener.on_keyword_hash_node_leave(node) }
|
737
738
|
end
|
738
739
|
|
739
|
-
# Dispatch enter and leave events for KeywordParameterNode nodes and continue
|
740
|
-
# walking the tree.
|
741
|
-
def visit_keyword_parameter_node(node)
|
742
|
-
listeners[:on_keyword_parameter_node_enter]&.each { |listener| listener.on_keyword_parameter_node_enter(node) }
|
743
|
-
super
|
744
|
-
listeners[:on_keyword_parameter_node_leave]&.each { |listener| listener.on_keyword_parameter_node_leave(node) }
|
745
|
-
end
|
746
|
-
|
747
740
|
# Dispatch enter and leave events for KeywordRestParameterNode nodes and continue
|
748
741
|
# walking the tree.
|
749
742
|
def visit_keyword_rest_parameter_node(node)
|
@@ -904,6 +897,14 @@ module Prism
|
|
904
897
|
listeners[:on_numbered_reference_read_node_leave]&.each { |listener| listener.on_numbered_reference_read_node_leave(node) }
|
905
898
|
end
|
906
899
|
|
900
|
+
# Dispatch enter and leave events for OptionalKeywordParameterNode nodes and continue
|
901
|
+
# walking the tree.
|
902
|
+
def visit_optional_keyword_parameter_node(node)
|
903
|
+
listeners[:on_optional_keyword_parameter_node_enter]&.each { |listener| listener.on_optional_keyword_parameter_node_enter(node) }
|
904
|
+
super
|
905
|
+
listeners[:on_optional_keyword_parameter_node_leave]&.each { |listener| listener.on_optional_keyword_parameter_node_leave(node) }
|
906
|
+
end
|
907
|
+
|
907
908
|
# Dispatch enter and leave events for OptionalParameterNode nodes and continue
|
908
909
|
# walking the tree.
|
909
910
|
def visit_optional_parameter_node(node)
|
@@ -1008,12 +1009,12 @@ module Prism
|
|
1008
1009
|
listeners[:on_regular_expression_node_leave]&.each { |listener| listener.on_regular_expression_node_leave(node) }
|
1009
1010
|
end
|
1010
1011
|
|
1011
|
-
# Dispatch enter and leave events for
|
1012
|
+
# Dispatch enter and leave events for RequiredKeywordParameterNode nodes and continue
|
1012
1013
|
# walking the tree.
|
1013
|
-
def
|
1014
|
-
listeners[:
|
1014
|
+
def visit_required_keyword_parameter_node(node)
|
1015
|
+
listeners[:on_required_keyword_parameter_node_enter]&.each { |listener| listener.on_required_keyword_parameter_node_enter(node) }
|
1015
1016
|
super
|
1016
|
-
listeners[:
|
1017
|
+
listeners[:on_required_keyword_parameter_node_leave]&.each { |listener| listener.on_required_keyword_parameter_node_leave(node) }
|
1017
1018
|
end
|
1018
1019
|
|
1019
1020
|
# Dispatch enter and leave events for RequiredParameterNode nodes and continue
|
@@ -1216,7 +1217,7 @@ module Prism
|
|
1216
1217
|
listeners[:on_yield_node_leave]&.each { |listener| listener.on_yield_node_leave(node) }
|
1217
1218
|
end
|
1218
1219
|
|
1219
|
-
class DispatchOnce < Visitor
|
1220
|
+
class DispatchOnce < Visitor # :nodoc:
|
1220
1221
|
attr_reader :listeners
|
1221
1222
|
|
1222
1223
|
def initialize(listeners)
|
@@ -1727,12 +1728,6 @@ module Prism
|
|
1727
1728
|
listeners[:on_keyword_hash_node_leave]&.each { |listener| listener.on_keyword_hash_node_leave(node) }
|
1728
1729
|
end
|
1729
1730
|
|
1730
|
-
# Dispatch enter and leave events for KeywordParameterNode nodes.
|
1731
|
-
def visit_keyword_parameter_node(node)
|
1732
|
-
listeners[:on_keyword_parameter_node_enter]&.each { |listener| listener.on_keyword_parameter_node_enter(node) }
|
1733
|
-
listeners[:on_keyword_parameter_node_leave]&.each { |listener| listener.on_keyword_parameter_node_leave(node) }
|
1734
|
-
end
|
1735
|
-
|
1736
1731
|
# Dispatch enter and leave events for KeywordRestParameterNode nodes.
|
1737
1732
|
def visit_keyword_rest_parameter_node(node)
|
1738
1733
|
listeners[:on_keyword_rest_parameter_node_enter]&.each { |listener| listener.on_keyword_rest_parameter_node_enter(node) }
|
@@ -1853,6 +1848,12 @@ module Prism
|
|
1853
1848
|
listeners[:on_numbered_reference_read_node_leave]&.each { |listener| listener.on_numbered_reference_read_node_leave(node) }
|
1854
1849
|
end
|
1855
1850
|
|
1851
|
+
# Dispatch enter and leave events for OptionalKeywordParameterNode nodes.
|
1852
|
+
def visit_optional_keyword_parameter_node(node)
|
1853
|
+
listeners[:on_optional_keyword_parameter_node_enter]&.each { |listener| listener.on_optional_keyword_parameter_node_enter(node) }
|
1854
|
+
listeners[:on_optional_keyword_parameter_node_leave]&.each { |listener| listener.on_optional_keyword_parameter_node_leave(node) }
|
1855
|
+
end
|
1856
|
+
|
1856
1857
|
# Dispatch enter and leave events for OptionalParameterNode nodes.
|
1857
1858
|
def visit_optional_parameter_node(node)
|
1858
1859
|
listeners[:on_optional_parameter_node_enter]&.each { |listener| listener.on_optional_parameter_node_enter(node) }
|
@@ -1931,10 +1932,10 @@ module Prism
|
|
1931
1932
|
listeners[:on_regular_expression_node_leave]&.each { |listener| listener.on_regular_expression_node_leave(node) }
|
1932
1933
|
end
|
1933
1934
|
|
1934
|
-
# Dispatch enter and leave events for
|
1935
|
-
def
|
1936
|
-
listeners[:
|
1937
|
-
listeners[:
|
1935
|
+
# Dispatch enter and leave events for RequiredKeywordParameterNode nodes.
|
1936
|
+
def visit_required_keyword_parameter_node(node)
|
1937
|
+
listeners[:on_required_keyword_parameter_node_enter]&.each { |listener| listener.on_required_keyword_parameter_node_enter(node) }
|
1938
|
+
listeners[:on_required_keyword_parameter_node_leave]&.each { |listener| listener.on_required_keyword_parameter_node_leave(node) }
|
1938
1939
|
end
|
1939
1940
|
|
1940
1941
|
# Dispatch enter and leave events for RequiredParameterNode nodes.
|
data/lib/prism/dsl.rb
CHANGED
@@ -63,8 +63,8 @@ module Prism
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Create a new ArgumentsNode node
|
66
|
-
def ArgumentsNode(arguments, location = Location())
|
67
|
-
ArgumentsNode.new(arguments, location)
|
66
|
+
def ArgumentsNode(arguments, flags, location = Location())
|
67
|
+
ArgumentsNode.new(arguments, flags, location)
|
68
68
|
end
|
69
69
|
|
70
70
|
# Create a new ArrayNode node
|
@@ -358,8 +358,8 @@ module Prism
|
|
358
358
|
end
|
359
359
|
|
360
360
|
# Create a new HashPatternNode node
|
361
|
-
def HashPatternNode(constant,
|
362
|
-
HashPatternNode.new(constant,
|
361
|
+
def HashPatternNode(constant, elements, rest, opening_loc, closing_loc, location = Location())
|
362
|
+
HashPatternNode.new(constant, elements, rest, opening_loc, closing_loc, location)
|
363
363
|
end
|
364
364
|
|
365
365
|
# Create a new IfNode node
|
@@ -462,11 +462,6 @@ module Prism
|
|
462
462
|
KeywordHashNode.new(elements, location)
|
463
463
|
end
|
464
464
|
|
465
|
-
# Create a new KeywordParameterNode node
|
466
|
-
def KeywordParameterNode(name, name_loc, value, location = Location())
|
467
|
-
KeywordParameterNode.new(name, name_loc, value, location)
|
468
|
-
end
|
469
|
-
|
470
465
|
# Create a new KeywordRestParameterNode node
|
471
466
|
def KeywordRestParameterNode(name, name_loc, operator_loc, location = Location())
|
472
467
|
KeywordRestParameterNode.new(name, name_loc, operator_loc, location)
|
@@ -538,13 +533,13 @@ module Prism
|
|
538
533
|
end
|
539
534
|
|
540
535
|
# Create a new MultiTargetNode node
|
541
|
-
def MultiTargetNode(
|
542
|
-
MultiTargetNode.new(
|
536
|
+
def MultiTargetNode(lefts, rest, rights, lparen_loc, rparen_loc, location = Location())
|
537
|
+
MultiTargetNode.new(lefts, rest, rights, lparen_loc, rparen_loc, location)
|
543
538
|
end
|
544
539
|
|
545
540
|
# Create a new MultiWriteNode node
|
546
|
-
def MultiWriteNode(
|
547
|
-
MultiWriteNode.new(
|
541
|
+
def MultiWriteNode(lefts, rest, rights, lparen_loc, rparen_loc, operator_loc, value, location = Location())
|
542
|
+
MultiWriteNode.new(lefts, rest, rights, lparen_loc, rparen_loc, operator_loc, value, location)
|
548
543
|
end
|
549
544
|
|
550
545
|
# Create a new NextNode node
|
@@ -567,6 +562,11 @@ module Prism
|
|
567
562
|
NumberedReferenceReadNode.new(number, location)
|
568
563
|
end
|
569
564
|
|
565
|
+
# Create a new OptionalKeywordParameterNode node
|
566
|
+
def OptionalKeywordParameterNode(name, name_loc, value, location = Location())
|
567
|
+
OptionalKeywordParameterNode.new(name, name_loc, value, location)
|
568
|
+
end
|
569
|
+
|
570
570
|
# Create a new OptionalParameterNode node
|
571
571
|
def OptionalParameterNode(name, name_loc, operator_loc, value, location = Location())
|
572
572
|
OptionalParameterNode.new(name, name_loc, operator_loc, value, location)
|
@@ -632,9 +632,9 @@ module Prism
|
|
632
632
|
RegularExpressionNode.new(opening_loc, content_loc, closing_loc, unescaped, flags, location)
|
633
633
|
end
|
634
634
|
|
635
|
-
# Create a new
|
636
|
-
def
|
637
|
-
|
635
|
+
# Create a new RequiredKeywordParameterNode node
|
636
|
+
def RequiredKeywordParameterNode(name, name_loc, location = Location())
|
637
|
+
RequiredKeywordParameterNode.new(name, name_loc, location)
|
638
638
|
end
|
639
639
|
|
640
640
|
# Create a new RequiredParameterNode node
|
data/lib/prism/ffi.rb
CHANGED
@@ -9,7 +9,7 @@ require "ffi"
|
|
9
9
|
module Prism
|
10
10
|
BACKEND = :FFI
|
11
11
|
|
12
|
-
module LibRubyParser
|
12
|
+
module LibRubyParser # :nodoc:
|
13
13
|
extend FFI::Library
|
14
14
|
|
15
15
|
# Define the library that we will be pulling functions from. Note that this
|
@@ -69,9 +69,10 @@ module Prism
|
|
69
69
|
load_exported_functions_from(
|
70
70
|
"prism.h",
|
71
71
|
"pm_version",
|
72
|
-
"
|
73
|
-
"
|
74
|
-
"
|
72
|
+
"pm_serialize_parse",
|
73
|
+
"pm_serialize_parse_comments",
|
74
|
+
"pm_serialize_lex",
|
75
|
+
"pm_serialize_parse_lex"
|
75
76
|
)
|
76
77
|
|
77
78
|
load_exported_functions_from(
|
@@ -94,7 +95,7 @@ module Prism
|
|
94
95
|
|
95
96
|
# This object represents a pm_buffer_t. We only use it as an opaque pointer,
|
96
97
|
# so it doesn't need to know the fields of pm_buffer_t.
|
97
|
-
class PrismBuffer
|
98
|
+
class PrismBuffer # :nodoc:
|
98
99
|
SIZEOF = LibRubyParser.pm_buffer_sizeof
|
99
100
|
|
100
101
|
attr_reader :pointer
|
@@ -132,7 +133,7 @@ module Prism
|
|
132
133
|
|
133
134
|
# This object represents a pm_string_t. We only use it as an opaque pointer,
|
134
135
|
# so it doesn't have to be an FFI::Struct.
|
135
|
-
class PrismString
|
136
|
+
class PrismString # :nodoc:
|
136
137
|
SIZEOF = LibRubyParser.pm_string_sizeof
|
137
138
|
|
138
139
|
attr_reader :pointer
|
@@ -166,14 +167,6 @@ module Prism
|
|
166
167
|
end
|
167
168
|
end
|
168
169
|
end
|
169
|
-
|
170
|
-
def self.dump_internal(source, source_size, filepath)
|
171
|
-
PrismBuffer.with do |buffer|
|
172
|
-
metadata = [filepath.bytesize, filepath.b, 0].pack("LA*L") if filepath
|
173
|
-
pm_parse_serialize(source, source_size, buffer.pointer, metadata)
|
174
|
-
buffer.read
|
175
|
-
end
|
176
|
-
end
|
177
170
|
end
|
178
171
|
|
179
172
|
# Mark the LibRubyParser module as private as it should only be called through
|
@@ -183,69 +176,153 @@ module Prism
|
|
183
176
|
# The version constant is set by reading the result of calling pm_version.
|
184
177
|
VERSION = LibRubyParser.pm_version.read_string
|
185
178
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
179
|
+
class << self
|
180
|
+
# Mirror the Prism.dump API by using the serialization API.
|
181
|
+
def dump(code, **options)
|
182
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
183
|
+
LibRubyParser.pm_serialize_parse(buffer.pointer, code, code.bytesize, dump_options(options))
|
184
|
+
buffer.read
|
185
|
+
end
|
186
|
+
end
|
190
187
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
188
|
+
# Mirror the Prism.dump_file API by using the serialization API.
|
189
|
+
def dump_file(filepath, **options)
|
190
|
+
LibRubyParser::PrismString.with(filepath) do |string|
|
191
|
+
dump(string.read, **options, filepath: filepath)
|
192
|
+
end
|
195
193
|
end
|
196
|
-
end
|
197
194
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
195
|
+
# Mirror the Prism.lex API by using the serialization API.
|
196
|
+
def lex(code, **options)
|
197
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
198
|
+
LibRubyParser.pm_serialize_lex(buffer.pointer, code, code.bytesize, dump_options(options))
|
199
|
+
Serialize.load_tokens(Source.new(code), buffer.read)
|
200
|
+
end
|
203
201
|
end
|
204
|
-
end
|
205
202
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
203
|
+
# Mirror the Prism.lex_file API by using the serialization API.
|
204
|
+
def lex_file(filepath, **options)
|
205
|
+
LibRubyParser::PrismString.with(filepath) do |string|
|
206
|
+
lex(string.read, **options, filepath: filepath)
|
207
|
+
end
|
210
208
|
end
|
211
|
-
end
|
212
209
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
210
|
+
# Mirror the Prism.parse API by using the serialization API.
|
211
|
+
def parse(code, **options)
|
212
|
+
Prism.load(code, dump(code, **options))
|
213
|
+
end
|
217
214
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
215
|
+
# Mirror the Prism.parse_file API by using the serialization API. This uses
|
216
|
+
# native strings instead of Ruby strings because it allows us to use mmap when
|
217
|
+
# it is available.
|
218
|
+
def parse_file(filepath, **options)
|
219
|
+
LibRubyParser::PrismString.with(filepath) do |string|
|
220
|
+
parse(string.read, **options, filepath: filepath)
|
221
|
+
end
|
224
222
|
end
|
225
|
-
end
|
226
223
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
LibRubyParser.pm_parse_lex_serialize(code, code.bytesize, buffer.pointer, metadata)
|
224
|
+
# Mirror the Prism.parse_comments API by using the serialization API.
|
225
|
+
def parse_comments(code, **options)
|
226
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
227
|
+
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, code, code.bytesize, dump_options(options))
|
232
228
|
|
233
|
-
|
234
|
-
|
229
|
+
source = Source.new(code)
|
230
|
+
loader = Serialize::Loader.new(source, buffer.read)
|
235
231
|
|
236
|
-
|
237
|
-
|
232
|
+
loader.load_header
|
233
|
+
loader.load_force_encoding
|
234
|
+
loader.load_start_line
|
235
|
+
loader.load_comments
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Mirror the Prism.parse_file_comments API by using the serialization
|
240
|
+
# API. This uses native strings instead of Ruby strings because it allows us
|
241
|
+
# to use mmap when it is available.
|
242
|
+
def parse_file_comments(filepath, **options)
|
243
|
+
LibRubyParser::PrismString.with(filepath) do |string|
|
244
|
+
parse_comments(string.read, **options, filepath: filepath)
|
245
|
+
end
|
246
|
+
end
|
238
247
|
|
239
|
-
|
248
|
+
# Mirror the Prism.parse_lex API by using the serialization API.
|
249
|
+
def parse_lex(code, **options)
|
250
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
251
|
+
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, code, code.bytesize, dump_options(options))
|
240
252
|
|
241
|
-
|
253
|
+
source = Source.new(code)
|
254
|
+
loader = Serialize::Loader.new(source, buffer.read)
|
255
|
+
|
256
|
+
tokens = loader.load_tokens
|
257
|
+
node, comments, magic_comments, errors, warnings = loader.load_nodes
|
258
|
+
tokens.each { |token,| token.value.force_encoding(loader.encoding) }
|
259
|
+
|
260
|
+
ParseResult.new([node, tokens], comments, magic_comments, errors, warnings, source)
|
261
|
+
end
|
242
262
|
end
|
243
|
-
end
|
244
263
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
264
|
+
# Mirror the Prism.parse_lex_file API by using the serialization API.
|
265
|
+
def parse_lex_file(filepath, **options)
|
266
|
+
LibRubyParser::PrismString.with(filepath) do |string|
|
267
|
+
parse_lex(string.read, **options, filepath: filepath)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
private
|
272
|
+
|
273
|
+
# Convert the given options into a serialized options string.
|
274
|
+
def dump_options(options)
|
275
|
+
template = +""
|
276
|
+
values = []
|
277
|
+
|
278
|
+
template << "L"
|
279
|
+
if (filepath = options[:filepath])
|
280
|
+
values.push(filepath.bytesize, filepath.b)
|
281
|
+
template << "A*"
|
282
|
+
else
|
283
|
+
values << 0
|
284
|
+
end
|
285
|
+
|
286
|
+
template << "L"
|
287
|
+
values << options.fetch(:line, 1)
|
288
|
+
|
289
|
+
template << "L"
|
290
|
+
if (encoding = options[:encoding])
|
291
|
+
name = encoding.name
|
292
|
+
values.push(name.bytesize, name.b)
|
293
|
+
template << "A*"
|
294
|
+
else
|
295
|
+
values << 0
|
296
|
+
end
|
297
|
+
|
298
|
+
template << "C"
|
299
|
+
values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
|
300
|
+
|
301
|
+
template << "C"
|
302
|
+
values << (options[:verbose] ? 0 : 1)
|
303
|
+
|
304
|
+
template << "L"
|
305
|
+
if (scopes = options[:scopes])
|
306
|
+
values << scopes.length
|
307
|
+
|
308
|
+
scopes.each do |scope|
|
309
|
+
template << "L"
|
310
|
+
values << scope.length
|
311
|
+
|
312
|
+
scope.each do |local|
|
313
|
+
name = local.name
|
314
|
+
template << "L"
|
315
|
+
values << name.bytesize
|
316
|
+
|
317
|
+
template << "A*"
|
318
|
+
values << name.b
|
319
|
+
end
|
320
|
+
end
|
321
|
+
else
|
322
|
+
values << 0
|
323
|
+
end
|
324
|
+
|
325
|
+
values.pack(template)
|
249
326
|
end
|
250
327
|
end
|
251
328
|
end
|