Project

General

Profile

Feature #1866 ยป redefinable_not.patch

implementation of redefinable not, against ruby_1_8 - shyouhei (Shyouhei Urabe), 08/03/2009 03:47 PM

View differences:

ChangeLog
Mon Aug 3 15:04:01 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
* parse.y (expr): bug fix to prevent SEGV
Sun Aug 2 21:23:49 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
* parse.y (expr): redefinable not operators. Backport from trunk.
* parse.y (op): ditto.
* parse.y (arg): ditto.
* object.c (rb_obj_not_match): new method.
* object.c (rb_obj_not_equal): ditto.
* object.c (rb_obj_not): ditto.
Sun Aug 2 06:08:17 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
* node.h (rb_thread_status): ISO C89 do not allow a comma at the end of enum.
object.c
VALUE rb_cFalseClass;
VALUE rb_cSymbol;
static ID id_eq, id_eql, id_inspect, id_init_copy;
static ID id_eq, id_eql, id_match, id_inspect, id_init_copy;
/*
* call-seq:
......
return rb_obj_id(obj);
}
/*
* call-seq:
* !obj => true or false
*
* Boolean negate.
*/
VALUE
rb_obj_not(VALUE obj)
{
return RTEST(obj) ? Qfalse : Qtrue;
}
/*
* call-seq:
* obj != other => true or false
*
* Returns true if two objects are not-equal, otherwise false.
*/
VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
return RTEST(result) ? Qfalse : Qtrue;
}
VALUE
rb_class_real(cl)
VALUE cl;
......
return Qfalse;
}
/*
* call-seq:
* obj !~ other => true or false
*
* Returns true if two objects do not match (using the <i>=~</i>
* method), otherwise false.
*/
static VALUE
rb_obj_not_match(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_match, 1, obj2);
return RTEST(result) ? Qfalse : Qtrue;
}
/**********************************************************************
* Document-class: Symbol
*
......
rb_define_method(rb_mKernel, "nil?", rb_false, 0);
rb_define_method(rb_mKernel, "==", rb_obj_equal, 1);
rb_define_method(rb_mKernel, "!", rb_obj_not, 0);
rb_define_method(rb_mKernel, "!=", rb_obj_not_equal, 1);
rb_define_method(rb_mKernel, "equal?", rb_obj_equal, 1);
rb_define_method(rb_mKernel, "===", rb_equal, 1);
rb_define_method(rb_mKernel, "=~", rb_obj_pattern_match, 1);
rb_define_method(rb_mKernel, "!~", rb_obj_not_match, 1);
rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1);
......
id_eq = rb_intern("==");
id_eql = rb_intern("eql?");
id_match = rb_intern("match");
id_inspect = rb_intern("inspect");
id_init_copy = rb_intern("initialize_copy");
}
parse.y
static NODE *cond();
static NODE *logop();
static int cond_negative();
static NODE *newline_node();
static void fixpos();
......
{
$$ = NEW_IF(cond($3), remove_begin($1), 0);
fixpos($$, $3);
if (cond_negative(&$$->nd_cond)) {
$$->nd_else = $$->nd_body;
$$->nd_body = 0;
}
}
| stmt kUNLESS_MOD expr_value
{
$$ = NEW_UNLESS(cond($3), remove_begin($1), 0);
fixpos($$, $3);
if (cond_negative(&$$->nd_cond)) {
$$->nd_body = $$->nd_else;
$$->nd_else = 0;
}
}
| stmt kWHILE_MOD expr_value
{
......
else {
$$ = NEW_WHILE(cond($3), $1, 1);
}
if (cond_negative(&$$->nd_cond)) {
nd_set_type($$, NODE_UNTIL);
}
}
| stmt kUNTIL_MOD expr_value
{
......
else {
$$ = NEW_UNTIL(cond($3), $1, 1);
}
if (cond_negative(&$$->nd_cond)) {
nd_set_type($$, NODE_WHILE);
}
}
| stmt kRESCUE_MOD stmt
{
......
}
| kNOT expr
{
$$ = NEW_NOT(cond($2));
$$ = call_op($2, '!', 0, 0);
}
| '!' command_call
{
$$ = NEW_NOT(cond($2));
$$ = call_op($2, '!', 0, 0);
}
| arg
;
......
| tEQ { $$ = tEQ; }
| tEQQ { $$ = tEQQ; }
| tMATCH { $$ = tMATCH; }
| tNMATCH { $$ = tNMATCH; }
| '>' { $$ = '>'; }
| tGEQ { $$ = tGEQ; }
| '<' { $$ = '<'; }
| tLEQ { $$ = tLEQ; }
| tNEQ { $$ = tNEQ; }
| tLSHFT { $$ = tLSHFT; }
| tRSHFT { $$ = tRSHFT; }
| '+' { $$ = '+'; }
......
| '/' { $$ = '/'; }
| '%' { $$ = '%'; }
| tPOW { $$ = tPOW; }
| '!' { $$ = '!'; }
| '~' { $$ = '~'; }
| tUPLUS { $$ = tUPLUS; }
| tUMINUS { $$ = tUMINUS; }
......
}
| arg tNEQ arg
{
$$ = NEW_NOT(call_op($1, tEQ, 1, $3));
$$ = call_op($1, tNEQ, 1, $3);
}
| arg tMATCH arg
{
......
}
| arg tNMATCH arg
{
$$ = NEW_NOT(match_gen($1, $3));
$$ = call_op($1, tNMATCH, 1, $3);
}
| '!' arg
{
$$ = NEW_NOT(cond($2));
$$ = call_op($2, '!', 0, 0);
}
| '~' arg
{
......
{
$$ = NEW_IF(cond($2), $4, $5);
fixpos($$, $2);
if (cond_negative(&$$->nd_cond)) {
NODE *tmp = $$->nd_body;
$$->nd_body = $$->nd_else;
$$->nd_else = tmp;
}
}
| kUNLESS expr_value then
compstmt
......
{
$$ = NEW_UNLESS(cond($2), $4, $5);
fixpos($$, $2);
if (cond_negative(&$$->nd_cond)) {
NODE *tmp = $$->nd_body;
$$->nd_body = $$->nd_else;
$$->nd_else = tmp;
}
}
| kWHILE {COND_PUSH(1);} expr_value do {COND_POP();}
compstmt
......
{
$$ = NEW_WHILE(cond($3), $6, 1);
fixpos($$, $3);
if (cond_negative(&$$->nd_cond)) {
nd_set_type($$, NODE_UNTIL);
}
}
| kUNTIL {COND_PUSH(1);} expr_value do {COND_POP();}
compstmt
......
{
$$ = NEW_UNTIL(cond($3), $6, 1);
fixpos($$, $3);
if (cond_negative(&$$->nd_cond)) {
nd_set_type($$, NODE_WHILE);
}
}
| kCASE expr_value opt_terms
case_body
......
return c;
case '!':
lex_state = EXPR_BEG;
if ((c = nextc()) == '=') {
c = nextc();
if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) {
lex_state = EXPR_ARG;
if (c == '@') {
return '!';
}
}
else {
lex_state = EXPR_BEG;
}
if (c == '=') {
return tNEQ;
}
if (c == '~') {
......
return NEW_NODE(type, left, right, 0);
}
static int
cond_negative(nodep)
NODE **nodep;
{
NODE *c = *nodep;
if (!c) return 0;
switch (nd_type(c)) {
case NODE_NOT:
*nodep = c->nd_body;
return 1;
case NODE_NEWLINE:
if (c->nd_next && nd_type(c->nd_next) == NODE_NOT) {
c->nd_next = c->nd_next->nd_body;
return 1;
}
}
return 0;
}
static void
no_blockarg(node)
NODE *node;
......
{'|', "|"},
{'^', "^"},
{'&', "&"},
{'!', "!"},
{tCMP, "<=>"},
{'>', ">"},
{tGEQ, ">="},
......
{tNEQ, "!="},
{tMATCH, "=~"},
{tNMATCH, "!~"},
{'!', "!"},
{'~', "~"},
{'!', "!(unary)"},
{'~', "~(unary)"},
{'!', "!@"},
{'~', "~@"},
{'!', "!"},
{'!', "!(unary)"},
{'!', "!@"},
{tAREF, "[]"},
{tASET, "[]="},
{tLSHFT, "<<"},
    (1-1/1)