This project is closed and read-only.
Feature #1866 ยป redefinable_not.patch
| 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, "<<"},
|
||