prism 0.15.1 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|