summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2023-09-28 12:27:04 -0400
committerKevin Newton <kddnewton@gmail.com>2023-09-28 15:13:09 -0400
commit41d3e23582b3030a652919ee10fda114d7eb5626 (patch)
treee6f7a429125d9474a9ef889cba6175bf163bff7b
parent64da9be3af4f7dbeb276df0168b70bdb52af7c4f (diff)
Support the AlternationPatternNode
-rw-r--r--prism_compile.c28
-rw-r--r--test/ruby/test_compile_prism.rb24
2 files changed, 44 insertions, 8 deletions
diff --git a/prism_compile.c b/prism_compile.c
index d26130bd71..0aee358c8b 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -639,9 +639,33 @@ pm_compile_pattern(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const re
case PM_UNLESS_NODE:
rb_bug("Unless guards on pattern matching not yet supported.");
break;
- case PM_ALTERNATION_PATTERN_NODE:
- rb_bug("Alternation pattern matching not yet supported.");
+ case PM_ALTERNATION_PATTERN_NODE: {
+ // Alternation patterns allow you to specify multiple patterns in a
+ // single expression using the | operator.
+ pm_alternation_pattern_node_t *cast = (pm_alternation_pattern_node_t *) node;
+
+ LABEL *matched_left_label = NEW_LABEL(lineno);
+ LABEL *unmatched_left_label = NEW_LABEL(lineno);
+
+ // First, we're going to attempt to match against the left pattern. If
+ // that pattern matches, then we'll skip matching the right pattern.
+ ADD_INSN(ret, &dummy_line_node, dup);
+ pm_compile_pattern(iseq, cast->left, ret, src, compile_context, matched_left_label, unmatched_left_label);
+
+ // If we get here, then we matched on the left pattern. In this case we
+ // should pop out the duplicate value that we preemptively added to
+ // match against the right pattern and then jump to the match label.
+ ADD_LABEL(ret, matched_left_label);
+ ADD_INSN(ret, &dummy_line_node, pop);
+ ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
+ ADD_INSN(ret, &dummy_line_node, putnil);
+
+ // If we get here, then we didn't match on the left pattern. In this
+ // case we attempt to match against the right pattern.
+ ADD_LABEL(ret, unmatched_left_label);
+ pm_compile_pattern(iseq, cast->right, ret, src, compile_context, matched_label, unmatched_label);
break;
+ }
case PM_CAPTURE_PATTERN_NODE:
rb_bug("Capture pattern matching not yet supported.");
break;
diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb
index c74ecfef8c..d3fdfd68f1 100644
--- a/test/ruby/test_compile_prism.rb
+++ b/test/ruby/test_compile_prism.rb
@@ -338,6 +338,13 @@ module Prism
# Pattern matching #
############################################################################
+ def test_AlternationPatternNode
+ test_prism_eval("1 in 1 | 2")
+ test_prism_eval("1 in 2 | 1")
+ test_prism_eval("1 in 2 | 3 | 4 | 1")
+ test_prism_eval("1 in 2 | 3")
+ end
+
def test_MatchPredicateNode
test_prism_eval("1 in 1")
test_prism_eval("1.0 in 1.0")
@@ -355,11 +362,6 @@ module Prism
test_prism_eval("5 in 0..10")
test_prism_eval("5 in 0...10")
- test_prism_eval("module Prism; @@prism = 1; 1 in ^@@prism; end")
- test_prism_eval("module Prism; @prism = 1; 1 in ^@prism; end")
- test_prism_eval("$prism = 1; 1 in ^$prism")
- test_prism_eval("prism = 1; 1 in ^prism")
-
test_prism_eval("[\"5\"] in %w[5]")
test_prism_eval("Prism in Prism")
@@ -370,11 +372,21 @@ module Prism
test_prism_eval("\"foo\" in /.../")
test_prism_eval("\"foo1\" in /...\#{1}/")
test_prism_eval("4 in ->(v) { v.even? }")
- test_prism_eval("4 in ^(4)")
test_prism_eval("1 in 2")
end
+ def test_PinnedExpressionNode
+ test_prism_eval("4 in ^(4)")
+ end
+
+ def test_PinnedVariableNode
+ test_prism_eval("module Prism; @@prism = 1; 1 in ^@@prism; end")
+ test_prism_eval("module Prism; @prism = 1; 1 in ^@prism; end")
+ test_prism_eval("$prism = 1; 1 in ^$prism")
+ test_prism_eval("prism = 1; 1 in ^prism")
+ end
+
private
def compare_eval(source)