From: Alan Moore Date: 2001-10-06T07:21:28+09:00 Subject: [ruby-talk:22145] Match expressions Hi all, I'm writing the Regexp class for JRuby, and I found some- thing in the way Ruby parses/evaluates match expressions that I don't understand. I've excerpted the relevant portions of the code below. Here's how I read it: When the parser sees a =~ operator, it calls the match_gen function to create an appropriate node. If the parser can identify the left-hand node (L) as a regex, it returns a NODE_MATCH2 node, with L as the receiver and R (the right-hand node) as the argument. Otherwise, if R is obviously a regex, it returns a NODE_MATCH3, with R as the receiver and L as the argument. And if neither of those is true, it returns a generic method-call node, equivalent to L.match(R). When this node gets evaluated (in eval.c, below), Ruby evals L and R (resulting in l and r), and if the node's type is NODE_MATCH2, simply calls l.match(r). However, if the type is NODE_MATCH3, instead of calling r.match(l), it checks whether r is a string and, if so, calls l.match(r). This makes no sense to me: we already know that R was a regex, so how could r end up being a string? Then, when that check fails, it uses rb_funcall to call the "=~" method on r, as though it's still not sure that r is a regex. Can anyone explain what a NODE_MATCH3 is supposed to repre- sent? Because it looks to me like all it does is slow things down slightly by forcing a polymorphic method call when it could be calling r.match(l) directly. In other words, match_gen should only return a NODE_MATCH2 (with L and R swapped, if appropriate) or a CALL, and there's no need for NODE_MATCH3 at all. What am I missing? --Alan ================= match_gen from parse.c ================== static NODE* match_gen(node1, node2) NODE *node1; NODE *node2; { local_cnt('~'); switch (nd_type(node1)) { case NODE_DREGX: case NODE_DREGX_ONCE: return NEW_MATCH2(node1, node2); case NODE_LIT: if (TYPE(node1->nd_lit) == T_REGEXP) { return NEW_MATCH2(node1, node2); } } switch (nd_type(node2)) { case NODE_DREGX: case NODE_DREGX_ONCE: return NEW_MATCH3(node2, node1); case NODE_LIT: if (TYPE(node2->nd_lit) == T_REGEXP) { return NEW_MATCH3(node2, node1); } } return NEW_CALL(node1, tMATCH, NEW_LIST(node2)); } ================== rb_eval from eval.c =================== /* nodes for speed-up(literal match) */ case NODE_MATCH2: result = rb_reg_match(rb_eval(self,node->nd_recv), rb_eval(self,node->nd_value)); break; /* nodes for speed-up(literal match) */ case NODE_MATCH3: { VALUE r = rb_eval(self,node->nd_recv); VALUE l = rb_eval(self,node->nd_value); if (TYPE(r) == T_STRING) { result = rb_reg_match(l, r); } else { result = rb_funcall(r, match, 1, l); } } break;