diff options
| author | Kevin Newton <kddnewton@gmail.com> | 2023-09-28 12:27:04 -0400 |
|---|---|---|
| committer | Kevin Newton <kddnewton@gmail.com> | 2023-09-28 15:13:09 -0400 |
| commit | 41d3e23582b3030a652919ee10fda114d7eb5626 (patch) | |
| tree | e6f7a429125d9474a9ef889cba6175bf163bff7b | |
| parent | 64da9be3af4f7dbeb276df0168b70bdb52af7c4f (diff) | |
Support the AlternationPatternNode
| -rw-r--r-- | prism_compile.c | 28 | ||||
| -rw-r--r-- | test/ruby/test_compile_prism.rb | 24 |
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) |
