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

Thursday, June 11, 2009

It Is Difficult To Extend Ruby's Syntax of Defining a Method Without End

To define a method in a line, we may write such a code.

def f(x) x + 1 end

I tried to add this new syntax to Ruby.

def: f(x) x + 1

I thought I could add the syntax. It consists of:

  • keyword def (k_def in parse.y)
  • a char ':'
  • function name (fname in parse.y)
  • an expression (expr in parse.y)
  • the end of line (term in parse.y)

To skip the keyword end, I made a restriction of having only one expression in the definition of the new method. I thought it would work, but I found that it couldn't.

I had been struggling to implement it. I'll introduce one of my tries here.

diff --git a/parse.y b/parse.y
index 636f51f..203cd9c 100644
--- a/parse.y
+++ b/parse.y
@@ -2878,6 +2878,40 @@ primary                : literal
                         $$ = dispatch2(module, $2, $4);
                     %*/
                     }
+                | k_def ':' fname
+                    {
+                        $<id>$ = cur_mid;
+                        cur_mid = $3;
+                        in_def++;
+                    /*%%%*/
+                        local_push(0);
+                    /*%
+                    %*/
+                    }
+                  f_arglist
+                  expr
+                  term
+                    {
+                    /*%%%*/
+                        $$ = newline_node($6);
+
+                        void_stmts($$);
+                        fixup_nodes(&deferred_nodes);
+
+                        fixpos($$, $6);
+
+                        NODE *body = remove_begin($6);
+                        reduce_nodes(&body);
+                        $$ = NEW_DEFN($3, $5, body, NOEX_PRIVATE);
+                        fixpos($$, $5);
+                        fixpos($$->nd_defn, $5);
+                        local_pop();
+                    /*%
+                        $$ = dispatch3(defc, $3, $5, $6);
+                    %*/
+                        in_def--;
+                        cur_mid = $<id>4;
+                    }
 k_def fname
                     {
                         $<id>$ = cur_mid;

After applying this patch, a sample code

def: f(x) x + 2
p f(10)

will raise a syntax error:

/var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/v705342/390:3: syntax error, unexpected tIDENTIFIER, expecting $end
p f(10)
 ^

This tricky code can work well:

def: f(x) x + 2;;
p f(10) #=> 12

I still need a more work.

No comments:

Post a Comment

Followers