Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Wednesday, July 29, 2009

Incremental Operator in Ruby

Today I succeeded to add a new syntax "Pre Incremental Operator" like C's ++i into Ruby. The following code can run as you expect.

irb192

There are two possible ways what does ++i mean.

  1. Call succ and assign the result

    i = i.succ
    
  2. Call + with 1 and assign the result

    i = i.+(1)
    

I chose the former this time.

Patch

http://gist.github.com/158449

diff --git a/parse.y b/parse.y
index 10ac878..e02a1b1 100644
--- a/parse.y
+++ b/parse.y
@@ -685,6 +685,7 @@ static void token_info_pop(struct parser_params*, const char *token);
 %type <val> program reswords then do dot_or_colon
 %*/
 %token tUPLUS      /* unary+ */
+%token tINCR       /* ++var */
 %token tUMINUS     /* unary- */
 %token tPOW        /* ** */
 %token tCMP        /* <=> */
@@ -1783,6 +1784,7 @@ op        : '|'       { ifndef_ripper($$ = '|'); }
 '!'       { ifndef_ripper($$ = '!'); }
 '~'       { ifndef_ripper($$ = '~'); }
 tUPLUS    { ifndef_ripper($$ = tUPLUS); }
+       | tINCR     { ifndef_ripper($$ = tINCR); }
 tUMINUS   { ifndef_ripper($$ = tUMINUS); }
 tAREF     { ifndef_ripper($$ = tAREF); }
 tASET     { ifndef_ripper($$ = tASET); }
@@ -4130,6 +4132,15 @@ var_ref      : variable
      $$ = dispatch1(var_ref, $1);
        %*/
        }
+       | tINCR variable
+           {
+           /*%%%*/
+           $$ = assignable($2, 0);
+           $$->nd_value = NEW_CALL(gettable($$->nd_vid), rb_intern("succ"), 0);
+           /*%
+           $$ = dispatch2(unary, ripper_intern("++@"), $2);
+           %*/
+           }
    ;

 var_lhs        : variable
@@ -6773,6 +6784,9 @@ parser_yylex(struct parser_params *parser)

       case '+':
  c = nextc();
+   if (c == '+') {
+       return tINCR;
+   }
  if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) {
      lex_state = EXPR_ARG;
      if (c == '@') {
@@ -8277,6 +8291,7 @@ void_expr_gen(struct parser_params *parser, NODE *node)
    case '%':
    case tPOW:
    case tUPLUS:
+     case tINCR:
    case tUMINUS:
    case '|':
    case '^':
@@ -9111,6 +9126,7 @@ static const struct {
     {'-',  "-(binary)"},
     {tPOW, "**"},
     {tUPLUS,   "+@"},
+    {tINCR,    "++@"},
     {tUMINUS,  "-@"},
     {tCMP, "<=>"},
     {tGEQ, ">="},

Post Incremental Operator

I tried to add post incremental operator like C's i++, but I found that I couldn't.

There are two possible ways what does i++ mean.

  1. Store the original value, assign the result of succ, and return the original value

    tmp = i; i = i.succ; tmp
    
  2. Assign the result of + with 1, and return the result of - with 1

    (i = i.+(1)) - 1
    

The latter is easier to implement, because there's no storing a value.

No comments:

Post a Comment

Followers