prism 0.17.1 → 0.18.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 +30 -1
- data/Makefile +5 -5
- data/README.md +2 -2
- data/config.yml +26 -13
- data/docs/build_system.md +6 -6
- data/docs/building.md +1 -1
- data/docs/configuration.md +1 -0
- data/docs/encoding.md +68 -32
- data/docs/heredocs.md +1 -1
- data/docs/javascript.md +29 -1
- data/docs/ruby_api.md +14 -0
- data/ext/prism/api_node.c +74 -45
- data/ext/prism/extconf.rb +91 -127
- data/ext/prism/extension.c +1 -1
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +148 -133
- data/include/prism/diagnostic.h +27 -1
- data/include/prism/enc/pm_encoding.h +42 -1
- data/include/prism/parser.h +6 -0
- data/include/prism/version.h +3 -3
- data/lib/prism/compiler.rb +3 -3
- data/lib/prism/debug.rb +4 -0
- data/lib/prism/desugar_compiler.rb +1 -0
- data/lib/prism/dispatcher.rb +14 -14
- data/lib/prism/dot_visitor.rb +4334 -0
- data/lib/prism/dsl.rb +11 -11
- data/lib/prism/ffi.rb +3 -3
- data/lib/prism/mutation_compiler.rb +6 -6
- data/lib/prism/node.rb +182 -113
- data/lib/prism/node_ext.rb +61 -3
- data/lib/prism/parse_result.rb +46 -12
- data/lib/prism/serialize.rb +125 -131
- data/lib/prism/visitor.rb +3 -3
- data/lib/prism.rb +1 -0
- data/prism.gemspec +5 -1
- data/rbi/prism.rbi +83 -54
- data/sig/prism.rbs +47 -32
- data/src/diagnostic.c +61 -3
- data/src/enc/pm_big5.c +63 -0
- data/src/enc/pm_cp51932.c +57 -0
- data/src/enc/pm_euc_jp.c +10 -0
- data/src/enc/pm_gbk.c +5 -2
- data/src/enc/pm_tables.c +1478 -148
- data/src/node.c +33 -21
- data/src/prettyprint.c +1027 -925
- data/src/prism.c +925 -374
- data/src/regexp.c +12 -12
- data/src/serialize.c +36 -9
- metadata +6 -2
data/lib/prism/dsl.rb
CHANGED
@@ -152,6 +152,11 @@ module Prism
|
|
152
152
|
CapturePatternNode.new(value, target, operator_loc, location)
|
153
153
|
end
|
154
154
|
|
155
|
+
# Create a new CaseMatchNode node
|
156
|
+
def CaseMatchNode(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location = Location())
|
157
|
+
CaseMatchNode.new(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location)
|
158
|
+
end
|
159
|
+
|
155
160
|
# Create a new CaseNode node
|
156
161
|
def CaseNode(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location = Location())
|
157
162
|
CaseNode.new(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location)
|
@@ -363,8 +368,8 @@ module Prism
|
|
363
368
|
end
|
364
369
|
|
365
370
|
# Create a new IfNode node
|
366
|
-
def IfNode(if_keyword_loc, predicate, statements, consequent, end_keyword_loc, location = Location())
|
367
|
-
IfNode.new(if_keyword_loc, predicate, statements, consequent, end_keyword_loc, location)
|
371
|
+
def IfNode(if_keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location = Location())
|
372
|
+
IfNode.new(if_keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location)
|
368
373
|
end
|
369
374
|
|
370
375
|
# Create a new ImaginaryNode node
|
@@ -518,8 +523,8 @@ module Prism
|
|
518
523
|
end
|
519
524
|
|
520
525
|
# Create a new MatchWriteNode node
|
521
|
-
def MatchWriteNode(call,
|
522
|
-
MatchWriteNode.new(call,
|
526
|
+
def MatchWriteNode(call, targets, location = Location())
|
527
|
+
MatchWriteNode.new(call, targets, location)
|
523
528
|
end
|
524
529
|
|
525
530
|
# Create a new MissingNode node
|
@@ -702,11 +707,6 @@ module Prism
|
|
702
707
|
StatementsNode.new(body, location)
|
703
708
|
end
|
704
709
|
|
705
|
-
# Create a new StringConcatNode node
|
706
|
-
def StringConcatNode(left, right, location = Location())
|
707
|
-
StringConcatNode.new(left, right, location)
|
708
|
-
end
|
709
|
-
|
710
710
|
# Create a new StringNode node
|
711
711
|
def StringNode(flags, opening_loc, content_loc, closing_loc, unescaped, location = Location())
|
712
712
|
StringNode.new(flags, opening_loc, content_loc, closing_loc, unescaped, location)
|
@@ -733,8 +733,8 @@ module Prism
|
|
733
733
|
end
|
734
734
|
|
735
735
|
# Create a new UnlessNode node
|
736
|
-
def UnlessNode(keyword_loc, predicate, statements, consequent, end_keyword_loc, location = Location())
|
737
|
-
UnlessNode.new(keyword_loc, predicate, statements, consequent, end_keyword_loc, location)
|
736
|
+
def UnlessNode(keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location = Location())
|
737
|
+
UnlessNode.new(keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location)
|
738
738
|
end
|
739
739
|
|
740
740
|
# Create a new UntilNode node
|
data/lib/prism/ffi.rb
CHANGED
@@ -14,7 +14,7 @@ module Prism
|
|
14
14
|
|
15
15
|
# Define the library that we will be pulling functions from. Note that this
|
16
16
|
# must align with the build shared library from make/rake.
|
17
|
-
ffi_lib File.expand_path("../../build/
|
17
|
+
ffi_lib File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
|
18
18
|
|
19
19
|
# Convert a native C type declaration into a symbol that FFI understands.
|
20
20
|
# For example:
|
@@ -230,7 +230,7 @@ module Prism
|
|
230
230
|
loader = Serialize::Loader.new(source, buffer.read)
|
231
231
|
|
232
232
|
loader.load_header
|
233
|
-
loader.
|
233
|
+
loader.load_encoding
|
234
234
|
loader.load_start_line
|
235
235
|
loader.load_comments
|
236
236
|
end
|
@@ -299,7 +299,7 @@ module Prism
|
|
299
299
|
values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
|
300
300
|
|
301
301
|
template << "C"
|
302
|
-
values << (options
|
302
|
+
values << (options.fetch(:verbose, true) ? 0 : 1)
|
303
303
|
|
304
304
|
template << "L"
|
305
305
|
if (scopes = options[:scopes])
|
@@ -120,6 +120,11 @@ module Prism
|
|
120
120
|
node.copy(value: visit(node.value), target: visit(node.target))
|
121
121
|
end
|
122
122
|
|
123
|
+
# Copy a CaseMatchNode node
|
124
|
+
def visit_case_match_node(node)
|
125
|
+
node.copy(predicate: visit(node.predicate), conditions: visit_all(node.conditions), consequent: visit(node.consequent))
|
126
|
+
end
|
127
|
+
|
123
128
|
# Copy a CaseNode node
|
124
129
|
def visit_case_node(node)
|
125
130
|
node.copy(predicate: visit(node.predicate), conditions: visit_all(node.conditions), consequent: visit(node.consequent))
|
@@ -487,7 +492,7 @@ module Prism
|
|
487
492
|
|
488
493
|
# Copy a MatchWriteNode node
|
489
494
|
def visit_match_write_node(node)
|
490
|
-
node.copy(call: visit(node.call))
|
495
|
+
node.copy(call: visit(node.call), targets: visit_all(node.targets))
|
491
496
|
end
|
492
497
|
|
493
498
|
# Copy a MissingNode node
|
@@ -670,11 +675,6 @@ module Prism
|
|
670
675
|
node.copy(body: visit_all(node.body))
|
671
676
|
end
|
672
677
|
|
673
|
-
# Copy a StringConcatNode node
|
674
|
-
def visit_string_concat_node(node)
|
675
|
-
node.copy(left: visit(node.left), right: visit(node.right))
|
676
|
-
end
|
677
|
-
|
678
678
|
# Copy a StringNode node
|
679
679
|
def visit_string_node(node)
|
680
680
|
node.copy
|
data/lib/prism/node.rb
CHANGED
@@ -38,6 +38,11 @@ module Prism
|
|
38
38
|
end
|
39
39
|
q.current_group.break
|
40
40
|
end
|
41
|
+
|
42
|
+
# Convert this node into a graphviz dot graph string.
|
43
|
+
def to_dot
|
44
|
+
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
48
|
# Represents the use of the `alias` keyword to alias a global variable.
|
@@ -2734,6 +2739,142 @@ module Prism
|
|
2734
2739
|
end
|
2735
2740
|
end
|
2736
2741
|
|
2742
|
+
# Represents the use of a case statement for pattern matching.
|
2743
|
+
#
|
2744
|
+
# case true
|
2745
|
+
# in false
|
2746
|
+
# end
|
2747
|
+
# ^^^^^^^^^
|
2748
|
+
class CaseMatchNode < Node
|
2749
|
+
# attr_reader predicate: Node?
|
2750
|
+
attr_reader :predicate
|
2751
|
+
|
2752
|
+
# attr_reader conditions: Array[Node]
|
2753
|
+
attr_reader :conditions
|
2754
|
+
|
2755
|
+
# attr_reader consequent: ElseNode?
|
2756
|
+
attr_reader :consequent
|
2757
|
+
|
2758
|
+
# attr_reader case_keyword_loc: Location
|
2759
|
+
attr_reader :case_keyword_loc
|
2760
|
+
|
2761
|
+
# attr_reader end_keyword_loc: Location
|
2762
|
+
attr_reader :end_keyword_loc
|
2763
|
+
|
2764
|
+
# def initialize: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> void
|
2765
|
+
def initialize(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location)
|
2766
|
+
@predicate = predicate
|
2767
|
+
@conditions = conditions
|
2768
|
+
@consequent = consequent
|
2769
|
+
@case_keyword_loc = case_keyword_loc
|
2770
|
+
@end_keyword_loc = end_keyword_loc
|
2771
|
+
@location = location
|
2772
|
+
end
|
2773
|
+
|
2774
|
+
# def accept: (visitor: Visitor) -> void
|
2775
|
+
def accept(visitor)
|
2776
|
+
visitor.visit_case_match_node(self)
|
2777
|
+
end
|
2778
|
+
|
2779
|
+
# def child_nodes: () -> Array[nil | Node]
|
2780
|
+
def child_nodes
|
2781
|
+
[predicate, *conditions, consequent]
|
2782
|
+
end
|
2783
|
+
|
2784
|
+
# def compact_child_nodes: () -> Array[Node]
|
2785
|
+
def compact_child_nodes
|
2786
|
+
compact = []
|
2787
|
+
compact << predicate if predicate
|
2788
|
+
compact.concat(conditions)
|
2789
|
+
compact << consequent if consequent
|
2790
|
+
compact
|
2791
|
+
end
|
2792
|
+
|
2793
|
+
# def comment_targets: () -> Array[Node | Location]
|
2794
|
+
def comment_targets
|
2795
|
+
[*predicate, *conditions, *consequent, case_keyword_loc, end_keyword_loc]
|
2796
|
+
end
|
2797
|
+
|
2798
|
+
# def copy: (**params) -> CaseMatchNode
|
2799
|
+
def copy(**params)
|
2800
|
+
CaseMatchNode.new(
|
2801
|
+
params.fetch(:predicate) { predicate },
|
2802
|
+
params.fetch(:conditions) { conditions },
|
2803
|
+
params.fetch(:consequent) { consequent },
|
2804
|
+
params.fetch(:case_keyword_loc) { case_keyword_loc },
|
2805
|
+
params.fetch(:end_keyword_loc) { end_keyword_loc },
|
2806
|
+
params.fetch(:location) { location },
|
2807
|
+
)
|
2808
|
+
end
|
2809
|
+
|
2810
|
+
# def deconstruct: () -> Array[nil | Node]
|
2811
|
+
alias deconstruct child_nodes
|
2812
|
+
|
2813
|
+
# def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
|
2814
|
+
def deconstruct_keys(keys)
|
2815
|
+
{ predicate: predicate, conditions: conditions, consequent: consequent, case_keyword_loc: case_keyword_loc, end_keyword_loc: end_keyword_loc, location: location }
|
2816
|
+
end
|
2817
|
+
|
2818
|
+
# def case_keyword: () -> String
|
2819
|
+
def case_keyword
|
2820
|
+
case_keyword_loc.slice
|
2821
|
+
end
|
2822
|
+
|
2823
|
+
# def end_keyword: () -> String
|
2824
|
+
def end_keyword
|
2825
|
+
end_keyword_loc.slice
|
2826
|
+
end
|
2827
|
+
|
2828
|
+
# def inspect(inspector: NodeInspector) -> String
|
2829
|
+
def inspect(inspector = NodeInspector.new)
|
2830
|
+
inspector << inspector.header(self)
|
2831
|
+
if (predicate = self.predicate).nil?
|
2832
|
+
inspector << "├── predicate: ∅\n"
|
2833
|
+
else
|
2834
|
+
inspector << "├── predicate:\n"
|
2835
|
+
inspector << predicate.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix)
|
2836
|
+
end
|
2837
|
+
inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│ ", conditions)}"
|
2838
|
+
if (consequent = self.consequent).nil?
|
2839
|
+
inspector << "├── consequent: ∅\n"
|
2840
|
+
else
|
2841
|
+
inspector << "├── consequent:\n"
|
2842
|
+
inspector << consequent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix)
|
2843
|
+
end
|
2844
|
+
inspector << "├── case_keyword_loc: #{inspector.location(case_keyword_loc)}\n"
|
2845
|
+
inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n"
|
2846
|
+
inspector.to_str
|
2847
|
+
end
|
2848
|
+
|
2849
|
+
# Sometimes you want to check an instance of a node against a list of
|
2850
|
+
# classes to see what kind of behavior to perform. Usually this is done by
|
2851
|
+
# calling `[cls1, cls2].include?(node.class)` or putting the node into a
|
2852
|
+
# case statement and doing `case node; when cls1; when cls2; end`. Both of
|
2853
|
+
# these approaches are relatively slow because of the constant lookups,
|
2854
|
+
# method calls, and/or array allocations.
|
2855
|
+
#
|
2856
|
+
# Instead, you can call #type, which will return to you a symbol that you
|
2857
|
+
# can use for comparison. This is faster than the other approaches because
|
2858
|
+
# it uses a single integer comparison, but also because if you're on CRuby
|
2859
|
+
# you can take advantage of the fact that case statements with all symbol
|
2860
|
+
# keys will use a jump table.
|
2861
|
+
#
|
2862
|
+
# def type: () -> Symbol
|
2863
|
+
def type
|
2864
|
+
:case_match_node
|
2865
|
+
end
|
2866
|
+
|
2867
|
+
# Similar to #type, this method returns a symbol that you can use for
|
2868
|
+
# splitting on the type of the node without having to do a long === chain.
|
2869
|
+
# Note that like #type, it will still be slower than using == for a single
|
2870
|
+
# class, but should be faster in a case statement or an array comparison.
|
2871
|
+
#
|
2872
|
+
# def self.type: () -> Symbol
|
2873
|
+
def self.type
|
2874
|
+
:case_match_node
|
2875
|
+
end
|
2876
|
+
end
|
2877
|
+
|
2737
2878
|
# Represents the use of a case statement.
|
2738
2879
|
#
|
2739
2880
|
# case true
|
@@ -7387,6 +7528,9 @@ module Prism
|
|
7387
7528
|
# attr_reader predicate: Node
|
7388
7529
|
attr_reader :predicate
|
7389
7530
|
|
7531
|
+
# attr_reader then_keyword_loc: Location?
|
7532
|
+
attr_reader :then_keyword_loc
|
7533
|
+
|
7390
7534
|
# attr_reader statements: StatementsNode?
|
7391
7535
|
attr_reader :statements
|
7392
7536
|
|
@@ -7396,10 +7540,11 @@ module Prism
|
|
7396
7540
|
# attr_reader end_keyword_loc: Location?
|
7397
7541
|
attr_reader :end_keyword_loc
|
7398
7542
|
|
7399
|
-
# def initialize: (if_keyword_loc: Location?, predicate: Node, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> void
|
7400
|
-
def initialize(if_keyword_loc, predicate, statements, consequent, end_keyword_loc, location)
|
7543
|
+
# def initialize: (if_keyword_loc: Location?, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> void
|
7544
|
+
def initialize(if_keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location)
|
7401
7545
|
@if_keyword_loc = if_keyword_loc
|
7402
7546
|
@predicate = predicate
|
7547
|
+
@then_keyword_loc = then_keyword_loc
|
7403
7548
|
@statements = statements
|
7404
7549
|
@consequent = consequent
|
7405
7550
|
@end_keyword_loc = end_keyword_loc
|
@@ -7431,7 +7576,7 @@ module Prism
|
|
7431
7576
|
|
7432
7577
|
# def comment_targets: () -> Array[Node | Location]
|
7433
7578
|
def comment_targets
|
7434
|
-
[*if_keyword_loc, predicate, *statements, *consequent, *end_keyword_loc]
|
7579
|
+
[*if_keyword_loc, predicate, *then_keyword_loc, *statements, *consequent, *end_keyword_loc]
|
7435
7580
|
end
|
7436
7581
|
|
7437
7582
|
# def copy: (**params) -> IfNode
|
@@ -7439,6 +7584,7 @@ module Prism
|
|
7439
7584
|
IfNode.new(
|
7440
7585
|
params.fetch(:if_keyword_loc) { if_keyword_loc },
|
7441
7586
|
params.fetch(:predicate) { predicate },
|
7587
|
+
params.fetch(:then_keyword_loc) { then_keyword_loc },
|
7442
7588
|
params.fetch(:statements) { statements },
|
7443
7589
|
params.fetch(:consequent) { consequent },
|
7444
7590
|
params.fetch(:end_keyword_loc) { end_keyword_loc },
|
@@ -7451,7 +7597,7 @@ module Prism
|
|
7451
7597
|
|
7452
7598
|
# def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
|
7453
7599
|
def deconstruct_keys(keys)
|
7454
|
-
{ if_keyword_loc: if_keyword_loc, predicate: predicate, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location }
|
7600
|
+
{ if_keyword_loc: if_keyword_loc, predicate: predicate, then_keyword_loc: then_keyword_loc, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location }
|
7455
7601
|
end
|
7456
7602
|
|
7457
7603
|
# def if_keyword: () -> String?
|
@@ -7459,6 +7605,11 @@ module Prism
|
|
7459
7605
|
if_keyword_loc&.slice
|
7460
7606
|
end
|
7461
7607
|
|
7608
|
+
# def then_keyword: () -> String?
|
7609
|
+
def then_keyword
|
7610
|
+
then_keyword_loc&.slice
|
7611
|
+
end
|
7612
|
+
|
7462
7613
|
# def end_keyword: () -> String?
|
7463
7614
|
def end_keyword
|
7464
7615
|
end_keyword_loc&.slice
|
@@ -7470,6 +7621,7 @@ module Prism
|
|
7470
7621
|
inspector << "├── if_keyword_loc: #{inspector.location(if_keyword_loc)}\n"
|
7471
7622
|
inspector << "├── predicate:\n"
|
7472
7623
|
inspector << inspector.child_node(predicate, "│ ")
|
7624
|
+
inspector << "├── then_keyword_loc: #{inspector.location(then_keyword_loc)}\n"
|
7473
7625
|
if (statements = self.statements).nil?
|
7474
7626
|
inspector << "├── statements: ∅\n"
|
7475
7627
|
else
|
@@ -11132,13 +11284,13 @@ module Prism
|
|
11132
11284
|
# attr_reader call: CallNode
|
11133
11285
|
attr_reader :call
|
11134
11286
|
|
11135
|
-
# attr_reader
|
11136
|
-
attr_reader :
|
11287
|
+
# attr_reader targets: Array[Node]
|
11288
|
+
attr_reader :targets
|
11137
11289
|
|
11138
|
-
# def initialize: (call: CallNode,
|
11139
|
-
def initialize(call,
|
11290
|
+
# def initialize: (call: CallNode, targets: Array[Node], location: Location) -> void
|
11291
|
+
def initialize(call, targets, location)
|
11140
11292
|
@call = call
|
11141
|
-
@
|
11293
|
+
@targets = targets
|
11142
11294
|
@location = location
|
11143
11295
|
end
|
11144
11296
|
|
@@ -11149,24 +11301,24 @@ module Prism
|
|
11149
11301
|
|
11150
11302
|
# def child_nodes: () -> Array[nil | Node]
|
11151
11303
|
def child_nodes
|
11152
|
-
[call]
|
11304
|
+
[call, *targets]
|
11153
11305
|
end
|
11154
11306
|
|
11155
11307
|
# def compact_child_nodes: () -> Array[Node]
|
11156
11308
|
def compact_child_nodes
|
11157
|
-
[call]
|
11309
|
+
[call, *targets]
|
11158
11310
|
end
|
11159
11311
|
|
11160
11312
|
# def comment_targets: () -> Array[Node | Location]
|
11161
11313
|
def comment_targets
|
11162
|
-
[call]
|
11314
|
+
[call, *targets]
|
11163
11315
|
end
|
11164
11316
|
|
11165
11317
|
# def copy: (**params) -> MatchWriteNode
|
11166
11318
|
def copy(**params)
|
11167
11319
|
MatchWriteNode.new(
|
11168
11320
|
params.fetch(:call) { call },
|
11169
|
-
params.fetch(:
|
11321
|
+
params.fetch(:targets) { targets },
|
11170
11322
|
params.fetch(:location) { location },
|
11171
11323
|
)
|
11172
11324
|
end
|
@@ -11176,7 +11328,7 @@ module Prism
|
|
11176
11328
|
|
11177
11329
|
# def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
|
11178
11330
|
def deconstruct_keys(keys)
|
11179
|
-
{ call: call,
|
11331
|
+
{ call: call, targets: targets, location: location }
|
11180
11332
|
end
|
11181
11333
|
|
11182
11334
|
# def inspect(inspector: NodeInspector) -> String
|
@@ -11184,7 +11336,7 @@ module Prism
|
|
11184
11336
|
inspector << inspector.header(self)
|
11185
11337
|
inspector << "├── call:\n"
|
11186
11338
|
inspector << inspector.child_node(call, "│ ")
|
11187
|
-
inspector << "└──
|
11339
|
+
inspector << "└── targets: #{inspector.list("#{inspector.prefix} ", targets)}"
|
11188
11340
|
inspector.to_str
|
11189
11341
|
end
|
11190
11342
|
|
@@ -15076,100 +15228,6 @@ module Prism
|
|
15076
15228
|
end
|
15077
15229
|
end
|
15078
15230
|
|
15079
|
-
# Represents the use of compile-time string concatenation.
|
15080
|
-
#
|
15081
|
-
# "foo" "bar"
|
15082
|
-
# ^^^^^^^^^^^
|
15083
|
-
class StringConcatNode < Node
|
15084
|
-
# attr_reader left: Node
|
15085
|
-
attr_reader :left
|
15086
|
-
|
15087
|
-
# attr_reader right: Node
|
15088
|
-
attr_reader :right
|
15089
|
-
|
15090
|
-
# def initialize: (left: Node, right: Node, location: Location) -> void
|
15091
|
-
def initialize(left, right, location)
|
15092
|
-
@left = left
|
15093
|
-
@right = right
|
15094
|
-
@location = location
|
15095
|
-
end
|
15096
|
-
|
15097
|
-
# def accept: (visitor: Visitor) -> void
|
15098
|
-
def accept(visitor)
|
15099
|
-
visitor.visit_string_concat_node(self)
|
15100
|
-
end
|
15101
|
-
|
15102
|
-
# def child_nodes: () -> Array[nil | Node]
|
15103
|
-
def child_nodes
|
15104
|
-
[left, right]
|
15105
|
-
end
|
15106
|
-
|
15107
|
-
# def compact_child_nodes: () -> Array[Node]
|
15108
|
-
def compact_child_nodes
|
15109
|
-
[left, right]
|
15110
|
-
end
|
15111
|
-
|
15112
|
-
# def comment_targets: () -> Array[Node | Location]
|
15113
|
-
def comment_targets
|
15114
|
-
[left, right]
|
15115
|
-
end
|
15116
|
-
|
15117
|
-
# def copy: (**params) -> StringConcatNode
|
15118
|
-
def copy(**params)
|
15119
|
-
StringConcatNode.new(
|
15120
|
-
params.fetch(:left) { left },
|
15121
|
-
params.fetch(:right) { right },
|
15122
|
-
params.fetch(:location) { location },
|
15123
|
-
)
|
15124
|
-
end
|
15125
|
-
|
15126
|
-
# def deconstruct: () -> Array[nil | Node]
|
15127
|
-
alias deconstruct child_nodes
|
15128
|
-
|
15129
|
-
# def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
|
15130
|
-
def deconstruct_keys(keys)
|
15131
|
-
{ left: left, right: right, location: location }
|
15132
|
-
end
|
15133
|
-
|
15134
|
-
# def inspect(inspector: NodeInspector) -> String
|
15135
|
-
def inspect(inspector = NodeInspector.new)
|
15136
|
-
inspector << inspector.header(self)
|
15137
|
-
inspector << "├── left:\n"
|
15138
|
-
inspector << inspector.child_node(left, "│ ")
|
15139
|
-
inspector << "└── right:\n"
|
15140
|
-
inspector << inspector.child_node(right, " ")
|
15141
|
-
inspector.to_str
|
15142
|
-
end
|
15143
|
-
|
15144
|
-
# Sometimes you want to check an instance of a node against a list of
|
15145
|
-
# classes to see what kind of behavior to perform. Usually this is done by
|
15146
|
-
# calling `[cls1, cls2].include?(node.class)` or putting the node into a
|
15147
|
-
# case statement and doing `case node; when cls1; when cls2; end`. Both of
|
15148
|
-
# these approaches are relatively slow because of the constant lookups,
|
15149
|
-
# method calls, and/or array allocations.
|
15150
|
-
#
|
15151
|
-
# Instead, you can call #type, which will return to you a symbol that you
|
15152
|
-
# can use for comparison. This is faster than the other approaches because
|
15153
|
-
# it uses a single integer comparison, but also because if you're on CRuby
|
15154
|
-
# you can take advantage of the fact that case statements with all symbol
|
15155
|
-
# keys will use a jump table.
|
15156
|
-
#
|
15157
|
-
# def type: () -> Symbol
|
15158
|
-
def type
|
15159
|
-
:string_concat_node
|
15160
|
-
end
|
15161
|
-
|
15162
|
-
# Similar to #type, this method returns a symbol that you can use for
|
15163
|
-
# splitting on the type of the node without having to do a long === chain.
|
15164
|
-
# Note that like #type, it will still be slower than using == for a single
|
15165
|
-
# class, but should be faster in a case statement or an array comparison.
|
15166
|
-
#
|
15167
|
-
# def self.type: () -> Symbol
|
15168
|
-
def self.type
|
15169
|
-
:string_concat_node
|
15170
|
-
end
|
15171
|
-
end
|
15172
|
-
|
15173
15231
|
# Represents a string literal, a string contained within a `%w` list, or
|
15174
15232
|
# plain string content within an interpolated string.
|
15175
15233
|
#
|
@@ -15762,6 +15820,9 @@ module Prism
|
|
15762
15820
|
# attr_reader predicate: Node
|
15763
15821
|
attr_reader :predicate
|
15764
15822
|
|
15823
|
+
# attr_reader then_keyword_loc: Location?
|
15824
|
+
attr_reader :then_keyword_loc
|
15825
|
+
|
15765
15826
|
# attr_reader statements: StatementsNode?
|
15766
15827
|
attr_reader :statements
|
15767
15828
|
|
@@ -15771,10 +15832,11 @@ module Prism
|
|
15771
15832
|
# attr_reader end_keyword_loc: Location?
|
15772
15833
|
attr_reader :end_keyword_loc
|
15773
15834
|
|
15774
|
-
# def initialize: (keyword_loc: Location, predicate: Node, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> void
|
15775
|
-
def initialize(keyword_loc, predicate, statements, consequent, end_keyword_loc, location)
|
15835
|
+
# def initialize: (keyword_loc: Location, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> void
|
15836
|
+
def initialize(keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location)
|
15776
15837
|
@keyword_loc = keyword_loc
|
15777
15838
|
@predicate = predicate
|
15839
|
+
@then_keyword_loc = then_keyword_loc
|
15778
15840
|
@statements = statements
|
15779
15841
|
@consequent = consequent
|
15780
15842
|
@end_keyword_loc = end_keyword_loc
|
@@ -15806,7 +15868,7 @@ module Prism
|
|
15806
15868
|
|
15807
15869
|
# def comment_targets: () -> Array[Node | Location]
|
15808
15870
|
def comment_targets
|
15809
|
-
[keyword_loc, predicate, *statements, *consequent, *end_keyword_loc]
|
15871
|
+
[keyword_loc, predicate, *then_keyword_loc, *statements, *consequent, *end_keyword_loc]
|
15810
15872
|
end
|
15811
15873
|
|
15812
15874
|
# def copy: (**params) -> UnlessNode
|
@@ -15814,6 +15876,7 @@ module Prism
|
|
15814
15876
|
UnlessNode.new(
|
15815
15877
|
params.fetch(:keyword_loc) { keyword_loc },
|
15816
15878
|
params.fetch(:predicate) { predicate },
|
15879
|
+
params.fetch(:then_keyword_loc) { then_keyword_loc },
|
15817
15880
|
params.fetch(:statements) { statements },
|
15818
15881
|
params.fetch(:consequent) { consequent },
|
15819
15882
|
params.fetch(:end_keyword_loc) { end_keyword_loc },
|
@@ -15826,7 +15889,7 @@ module Prism
|
|
15826
15889
|
|
15827
15890
|
# def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location]
|
15828
15891
|
def deconstruct_keys(keys)
|
15829
|
-
{ keyword_loc: keyword_loc, predicate: predicate, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location }
|
15892
|
+
{ keyword_loc: keyword_loc, predicate: predicate, then_keyword_loc: then_keyword_loc, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location }
|
15830
15893
|
end
|
15831
15894
|
|
15832
15895
|
# def keyword: () -> String
|
@@ -15834,6 +15897,11 @@ module Prism
|
|
15834
15897
|
keyword_loc.slice
|
15835
15898
|
end
|
15836
15899
|
|
15900
|
+
# def then_keyword: () -> String?
|
15901
|
+
def then_keyword
|
15902
|
+
then_keyword_loc&.slice
|
15903
|
+
end
|
15904
|
+
|
15837
15905
|
# def end_keyword: () -> String?
|
15838
15906
|
def end_keyword
|
15839
15907
|
end_keyword_loc&.slice
|
@@ -15845,6 +15913,7 @@ module Prism
|
|
15845
15913
|
inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n"
|
15846
15914
|
inspector << "├── predicate:\n"
|
15847
15915
|
inspector << inspector.child_node(predicate, "│ ")
|
15916
|
+
inspector << "├── then_keyword_loc: #{inspector.location(then_keyword_loc)}\n"
|
15848
15917
|
if (statements = self.statements).nil?
|
15849
15918
|
inspector << "├── statements: ∅\n"
|
15850
15919
|
else
|
data/lib/prism/node_ext.rb
CHANGED
@@ -61,7 +61,8 @@ module Prism
|
|
61
61
|
end
|
62
62
|
|
63
63
|
class ConstantReadNode < Node
|
64
|
-
# Returns the list of parts for the full name of this constant.
|
64
|
+
# Returns the list of parts for the full name of this constant.
|
65
|
+
# For example: [:Foo]
|
65
66
|
def full_name_parts
|
66
67
|
[name]
|
67
68
|
end
|
@@ -73,7 +74,16 @@ module Prism
|
|
73
74
|
end
|
74
75
|
|
75
76
|
class ConstantPathNode < Node
|
76
|
-
#
|
77
|
+
# An error class raised when dynamic parts are found while computing a
|
78
|
+
# constant path's full name. For example:
|
79
|
+
# Foo::Bar::Baz -> does not raise because all parts of the constant path are
|
80
|
+
# simple constants
|
81
|
+
# var::Bar::Baz -> raises because the first part of the constant path is a
|
82
|
+
# local variable
|
83
|
+
class DynamicPartsInConstantPathError < StandardError; end
|
84
|
+
|
85
|
+
# Returns the list of parts for the full name of this constant path.
|
86
|
+
# For example: [:Foo, :Bar]
|
77
87
|
def full_name_parts
|
78
88
|
parts = [child.name]
|
79
89
|
current = parent
|
@@ -83,6 +93,10 @@ module Prism
|
|
83
93
|
current = current.parent
|
84
94
|
end
|
85
95
|
|
96
|
+
unless current.is_a?(ConstantReadNode)
|
97
|
+
raise DynamicPartsInConstantPathError, "Constant path contains dynamic parts. Cannot compute full name"
|
98
|
+
end
|
99
|
+
|
86
100
|
parts.unshift(current&.name || :"")
|
87
101
|
end
|
88
102
|
|
@@ -93,7 +107,8 @@ module Prism
|
|
93
107
|
end
|
94
108
|
|
95
109
|
class ConstantPathTargetNode < Node
|
96
|
-
# Returns the list of parts for the full name of this constant path.
|
110
|
+
# Returns the list of parts for the full name of this constant path.
|
111
|
+
# For example: [:Foo, :Bar]
|
97
112
|
def full_name_parts
|
98
113
|
(parent&.full_name_parts || [:""]).push(child.name)
|
99
114
|
end
|
@@ -103,4 +118,47 @@ module Prism
|
|
103
118
|
full_name_parts.join("::")
|
104
119
|
end
|
105
120
|
end
|
121
|
+
|
122
|
+
class ParametersNode < Node
|
123
|
+
# Mirrors the Method#parameters method.
|
124
|
+
def signature
|
125
|
+
names = []
|
126
|
+
|
127
|
+
requireds.each do |param|
|
128
|
+
names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
|
129
|
+
end
|
130
|
+
|
131
|
+
optionals.each { |param| names << [:opt, param.name] }
|
132
|
+
names << [:rest, rest.name || :*] if rest
|
133
|
+
|
134
|
+
posts.each do |param|
|
135
|
+
names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
|
136
|
+
end
|
137
|
+
|
138
|
+
# Regardless of the order in which the keywords were defined, the required
|
139
|
+
# keywords always come first followed by the optional keywords.
|
140
|
+
keyopt = []
|
141
|
+
keywords.each do |param|
|
142
|
+
if param.is_a?(OptionalKeywordParameterNode)
|
143
|
+
keyopt << param
|
144
|
+
else
|
145
|
+
names << [:keyreq, param.name]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
keyopt.each { |param| names << [:key, param.name] }
|
150
|
+
|
151
|
+
case keyword_rest
|
152
|
+
when ForwardingParameterNode
|
153
|
+
names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
|
154
|
+
when KeywordRestParameterNode
|
155
|
+
names << [:keyrest, keyword_rest.name || :**]
|
156
|
+
when NoKeywordsParameterNode
|
157
|
+
names << [:nokey]
|
158
|
+
end
|
159
|
+
|
160
|
+
names << [:block, block.name || :&] if block
|
161
|
+
names
|
162
|
+
end
|
163
|
+
end
|
106
164
|
end
|