Rのインタプリタを改造して->(){}で関数を書けるようにしてみた

何やったの

Rのインタプリタのソースコードを改造してfunction(x){ statement }をRubyのlambdaライクに->(x){ statement }と書けるようにした.


何がうれしいの

  • わざわざ"function"という長いキーワードを入力しなくて済む
  • 記号だけで関数が記述できる
  • ソースコードからアルファベットや数字を除外できる
  • アルファベットや数字を読めない子供にやさしい


->って元々はRight Assignmentですよね

Right Assignmentはなかったことになった.

パッチ

パッチは以下の通り.このパッチでRのソースファイルsrc/main/gram.yを修正してRをコンパイルすると,->(){}で関数が書けるようになる.R 2.12.1で動作確認済.

*** R-2.12.1.org/src/main/gram.y	2010-09-17 07:02:24.000000000 +0900
--- R-2.12.1/src/main/gram.y	2011-01-19 17:39:26.000000000 +0900
***************
*** 215,221 ****
  
  %token		END_OF_INPUT ERROR
  %token		STR_CONST NUM_CONST NULL_CONST SYMBOL FUNCTION 
! %token		LEFT_ASSIGN EQ_ASSIGN RIGHT_ASSIGN LBB
  %token		FOR IN IF ELSE WHILE NEXT BREAK REPEAT
  %token		GT GE LT LE EQ NE AND OR AND2 OR2
  %token		NS_GET NS_GET_INT
--- 215,221 ----
  
  %token		END_OF_INPUT ERROR
  %token		STR_CONST NUM_CONST NULL_CONST SYMBOL FUNCTION 
! %token		LEFT_ASSIGN EQ_ASSIGN /*RIGHT_ASSIGN*/ LBB
  %token		FOR IN IF ELSE WHILE NEXT BREAK REPEAT
  %token		GT GE LT LE EQ NE AND OR AND2 OR2
  %token		NS_GET NS_GET_INT
***************
*** 227,233 ****
  %left		ELSE
  %right		LEFT_ASSIGN
  %right		EQ_ASSIGN
! %left		RIGHT_ASSIGN
  %left		'~' TILDE
  %left		OR OR2
  %left		AND AND2
--- 227,233 ----
  %left		ELSE
  %right		LEFT_ASSIGN
  %right		EQ_ASSIGN
! /*%left		RIGHT_ASSIGN*/
  %left		'~' TILDE
  %left		OR OR2
  %left		AND AND2
***************
*** 295,301 ****
  	|	expr OR2 expr			{ $$ = xxbinary($2,$1,$3); }
  
  	|	expr LEFT_ASSIGN expr 		{ $$ = xxbinary($2,$1,$3); }
! 	|	expr RIGHT_ASSIGN expr 		{ $$ = xxbinary($2,$3,$1); }
  	|	FUNCTION '(' formlist ')' cr expr_or_assign %prec LOW
  						{ $$ = xxdefun($1,$3,$6); }
  	|	expr '(' sublist ')'		{ $$ = xxfuncall($1,$3); }
--- 295,301 ----
  	|	expr OR2 expr			{ $$ = xxbinary($2,$1,$3); }
  
  	|	expr LEFT_ASSIGN expr 		{ $$ = xxbinary($2,$1,$3); }
! 	/*|	expr RIGHT_ASSIGN expr 		{ $$ = xxbinary($2,$3,$1); }*/
  	|	FUNCTION '(' formlist ')' cr expr_or_assign %prec LOW
  						{ $$ = xxdefun($1,$3,$6); }
  	|	expr '(' sublist ')'		{ $$ = xxfuncall($1,$3); }
***************
*** 1533,1538 ****
--- 1533,1539 ----
      { "NA_character_", NUM_CONST  },
      { "NA_complex_", NUM_CONST  },
      { "function",   FUNCTION   },
+     { "->",         FUNCTION   },
      { "while",	    WHILE      },
      { "repeat",	    REPEAT     },
      { "for",	    FOR	       },
***************
*** 1687,1693 ****
  	"NULL_CONST",	"'NULL'",
  	"FUNCTION",	"'function'",
  	"EQ_ASSIGN",	"'='",
! 	"RIGHT_ASSIGN",	"'->'",
  	"LBB",		"'[['",
  	"FOR",		"'for'",
  	"IN",		"'in'",
--- 1688,1694 ----
  	"NULL_CONST",	"'NULL'",
  	"FUNCTION",	"'function'",
  	"EQ_ASSIGN",	"'='",
! 	/*"RIGHT_ASSIGN",	"'->'",*/
  	"LBB",		"'[['",
  	"FOR",		"'for'",
  	"IN",		"'in'",
***************
*** 2520,2533 ****
  	return LT;
      case '-':
  	if (nextchar('>')) {
! 	    if (nextchar('>')) {
! 		yylval = install("<<-");
! 		return RIGHT_ASSIGN;
! 	    }
! 	    else {
! 		yylval = install("<-");
! 		return RIGHT_ASSIGN;
  	    }
  	}
  	yylval = install("-");
  	return '-';
--- 2521,2540 ----
  	return LT;
      case '-':
  	if (nextchar('>')) {
!             /* -> : function */
! 	    if (FunctionLevel >= MAXNEST)
! 		error(_("functions nested too deeply in source code at line %d"), ParseState.xxlineno);
! 	    if ( FunctionLevel++ == 0 && GenerateCode) {
! 		strcpy((char *)FunctionSource, "function");
! 		SourcePtr = FunctionSource + 8;
  	    }
+ 	    FunctionStart[FunctionLevel] = SourcePtr - 8;
+ #if 0
+ 	    printf("%d,%d\n", SourcePtr - FunctionSource, FunctionLevel);
+ #endif
+ 
+             yylval = install("function");
+             return FUNCTION;
  	}
  	yylval = install("-");
  	return '-';
***************
*** 2764,2770 ****
      case '$':
      case '@':
      case LEFT_ASSIGN:
!     case RIGHT_ASSIGN:
      case EQ_ASSIGN:
  	EatLines = 1;
  	break;
--- 2771,2777 ----
      case '$':
      case '@':
      case LEFT_ASSIGN:
!     /*case RIGHT_ASSIGN:*/
      case EQ_ASSIGN:
  	EatLines = 1;
  	break;

これをgram.y.patchなどのファイル名で保存して,以下のようにR 2.12.1のsrc/main/gram.yに適用する.また,コンパイルの前にsrc/main/gram.cを手動で削除しておく.

$ tar zxvf R-2.12.1.tar.gz
$ cd R-2.12.1
$ patch -p1 < /path/to/gram.y.patch
$ rm src/main/gram.c

あとはconfigureとmakeを実行すればOK.

注意点

パッチ適用後にmake checkするとfailします.

以上

Happy Symbolic Programming!!!