prism 0.17.1 → 0.18.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 +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
|