aboutsummaryrefslogtreecommitdiffstats
path: root/prism_compile.c
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2023-09-28 12:51:33 -0400
committerKevin Newton <kddnewton@gmail.com>2023-09-28 15:13:09 -0400
commit9c8ba8467599e174d73241631add030478891f49 (patch)
tree839b99545ac6c13b305378462a9d9383f74f9ae6 /prism_compile.c
parentb1a28b05db87ff520807ccd55d34e69fcd6ea53c (diff)
downloadruby-9c8ba8467599e174d73241631add030478891f49.tar.gz
Support if and unless guards on patterns
Diffstat (limited to 'prism_compile.c')
-rw-r--r--prism_compile.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/prism_compile.c b/prism_compile.c
index 7e0786c1f5..5dee86a2b6 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -630,15 +630,43 @@ pm_compile_pattern(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const re
case PM_HASH_PATTERN_NODE:
rb_bug("Hash pattern matching not yet supported.");
break;
- case PM_IF_NODE:
- rb_bug("If guards on pattern matching not yet supported.");
- break;
- case PM_UNLESS_NODE:
- rb_bug("Unless guards on pattern matching not yet supported.");
- break;
case PM_CAPTURE_PATTERN_NODE:
rb_bug("Capture pattern matching not yet supported.");
break;
+ case PM_IF_NODE: {
+ // If guards can be placed on patterns to further limit matches based on
+ // a dynamic predicate. This looks like:
+ //
+ // case foo
+ // in bar if baz
+ // end
+ //
+ pm_if_node_t *cast = (pm_if_node_t *) node;
+
+ pm_compile_pattern(iseq, cast->statements->body.nodes[0], ret, src, compile_context, matched_label, unmatched_label, in_alternation_pattern);
+ PM_COMPILE_NOT_POPPED(cast->predicate);
+
+ ADD_INSNL(ret, &dummy_line_node, branchunless, unmatched_label);
+ ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
+ break;
+ }
+ case PM_UNLESS_NODE: {
+ // Unless guards can be placed on patterns to further limit matches
+ // based on a dynamic predicate. This looks like:
+ //
+ // case foo
+ // in bar unless baz
+ // end
+ //
+ pm_unless_node_t *cast = (pm_unless_node_t *) node;
+
+ pm_compile_pattern(iseq, cast->statements->body.nodes[0], ret, src, compile_context, matched_label, unmatched_label, in_alternation_pattern);
+ PM_COMPILE_NOT_POPPED(cast->predicate);
+
+ ADD_INSNL(ret, &dummy_line_node, branchif, unmatched_label);
+ ADD_INSNL(ret, &dummy_line_node, jump, matched_label);
+ break;
+ }
case PM_LOCAL_VARIABLE_TARGET_NODE: {
// Local variables can be targetted by placing identifiers in the place
// of a pattern. For example, foo in bar. This results in the value
@@ -651,9 +679,11 @@ pm_compile_pattern(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const re
// it's ambiguous which value should be used. So instead we indicate
// this with a compile error.
if (in_alternation_pattern) {
- const char *name = rb_id2name(pm_constant_id_lookup(compile_context, cast->name));
+ ID id = pm_constant_id_lookup(compile_context, cast->name);
+ const char *name = rb_id2name(id);
+
if (name && strlen(name) > 0 && name[0] != '_') {
- COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")", name);
+ COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id));
return COMPILE_NG;
}
}
@@ -733,6 +763,8 @@ pm_compile_pattern(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const re
rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
break;
}
+
+ return COMPILE_OK;
}
/*