lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I felt the need for a case statement in Lua, so I added one.
Unfortunately I had to change the virtual machine as well as the
compiler, because I couldn't figure out how to duplicate the element
on top of the stack using only the existing operators.
Still, Lua is so clean that I added or changed no more than 30 lines
of code.

I borrowed syntax from Modula-3 for the case statement (with one
slight change); here's an example:

  x = "bar"
  
  case x of
  | "foo" => y = 1
  | "bar" => y = 2
  else => y = 99  
  end
  
  print(x, y)

Some day when I have another hack attack, I'll improve the patch so
you can write multiple expressions to the left of the arrow.

This is a patch file for lua-2.5.  To build it, unpack the lua-2.5
distribution, change to the toplevel directory (called 'lua' in the
distribution), and run

  patch < this_patch_file
  (cd src; make parser)
  make

Norman Ramsey
nr@cs.virginia.edu


*** ./src/luac/dump.c	1997/04/13 05:24:05	1.1
--- ./src/luac/dump.c	1997/04/13 05:24:24
***************
*** 42,47 ****
--- 42,48 ----
  	case PUSH0:
  	case PUSH1:
  	case PUSH2:
+ 	case DUP:
  	case PUSHLOCAL0:
  	case PUSHLOCAL1:
  	case PUSHLOCAL2:
*** ./src/luac/print.c	1997/04/13 05:23:33	1.1
--- ./src/luac/print.c	1997/04/13 05:23:48
***************
*** 3,9 ****
  ** print bytecodes
  */
  
! char* rcs_print="$Id: print.c,v 1.11 1996/11/18 11:24:16 lhf Exp $";
  
  #include <stdio.h>
  #include <stdlib.h>
--- 3,9 ----
  ** print bytecodes
  */
  
! char* rcs_print="$Id: print.c,v 1.1 1997/04/13 05:23:33 nr Exp nr $";
  
  #include <stdio.h>
  #include <stdlib.h>
***************
*** 32,37 ****
--- 32,38 ----
  	case PUSH0:
  	case PUSH1:
  	case PUSH2:
+         case DUP:
  	case PUSHINDEXED:
  	case STOREINDEXED0:
  	case ADJUST0:
*** ./src/luac/print.h	1997/04/13 05:24:50	1.1
--- ./src/luac/print.h	1997/04/13 05:25:09
***************
*** 9,14 ****
--- 9,15 ----
   "PUSH0",
   "PUSH1",
   "PUSH2",
+  "DUP",
   "PUSHBYTE",
   "PUSHWORD",
   "PUSHFLOAT",
*** ./src/lex.c	1997/04/13 04:44:51	1.1
--- ./src/lex.c	1997/04/13 04:46:48
***************
*** 48,53 ****
--- 48,54 ----
      int token;
    } reserved [] = {
        {"and", AND},
+       {"case", CASE},
        {"do", DO},
        {"else", ELSE},
        {"elseif", ELSEIF},
***************
*** 57,62 ****
--- 58,64 ----
        {"local", LOCAL},
        {"nil", NIL},
        {"not", NOT},
+       {"of", OF},
        {"or", OR},
        {"repeat", REPEAT},
        {"return", RETURN},
***************
*** 187,194 ****
  
        case '=':
          save_and_next();
!         if (current != '=') return '=';
!         else { save_and_next(); return EQ; }
  
        case '<':
          save_and_next();
--- 189,197 ----
  
        case '=':
          save_and_next();
!         if (current == '>') { save_and_next(); return ARROW; }
!         else if (current == '=') { save_and_next(); return EQ; }
!         else return '=';
  
        case '<':
          save_and_next();
*** ./src/opcode.c	1997/04/13 05:25:23	1.1
--- ./src/opcode.c	1997/04/13 05:28:07
***************
*** 950,955 ****
--- 950,958 ----
       incr_top;
       break;
  
+    case DUP:
+      *top = *(top-1); incr_top; break;
+ 
     case PUSHBYTE: 
       tag(top) = LUA_T_NUMBER; nvalue(top) = *pc++; incr_top; break;
  
*** ./src/opcode.h	1997/04/13 05:23:02	1.1
--- ./src/opcode.h	1997/04/13 05:20:43
***************
*** 1,6 ****
  /*
  ** TeCGraf - PUC-Rio
! ** $Id: opcode.h,v 3.24 1996/11/01 12:46:59 roberto Exp $
  */
  
  #ifndef opcode_h
--- 1,6 ----
  /*
  ** TeCGraf - PUC-Rio
! ** $Id: opcode.h,v 1.1 1997/04/13 05:23:02 nr Exp nr $
  */
  
  #ifndef opcode_h
***************
*** 23,28 ****
--- 23,29 ----
  PUSH0,/*		-		0.0  */
  PUSH1,/*		-		1.0  */
  PUSH2,/*		-		2.0  */
+ DUP,/*                  x               - x x */
  PUSHBYTE,/*	b	-		(float)b  */
  PUSHWORD,/*	w	-		(float)w  */
  PUSHFLOAT,/*	f	-		f  */
*** ./src/undump.c	1997/04/13 05:48:22	1.1
--- ./src/undump.c	1997/04/13 05:29:13
***************
*** 3,9 ****
  ** load bytecodes from files
  */
  
! char* rcs_undump="$Id: undump.c,v 1.21 1996/11/18 11:18:29 lhf Exp $";
  
  #include <stdio.h>
  #include <string.h>
--- 3,9 ----
  ** load bytecodes from files
  */
  
! char* rcs_undump="$Id: undump.c,v 1.1 1997/04/13 05:48:22 nr Exp nr $";
  
  #include <stdio.h>
  #include <string.h>
***************
*** 36,41 ****
--- 36,42 ----
  	case PUSH0:
  	case PUSH1:
  	case PUSH2:
+ 	case DUP:
  	case PUSHLOCAL0:
  	case PUSHLOCAL1:
  	case PUSHLOCAL2:
*** src/lua.stx	1997/04/13 04:44:51	1.1
--- src/lua.stx	1997/04/13 05:30:26
***************
*** 426,436 ****
  
  %token WRONGTOKEN
  %token NIL
! %token IF THEN ELSE ELSEIF WHILE DO REPEAT UNTIL END
  %token RETURN
  %token LOCAL
  %token FUNCTION
  %token DOTS
  %token <vFloat> NUMBER
  %token <vWord>  STRING
  %token <pTStr>  NAME 
--- 426,437 ----
  
  %token WRONGTOKEN
  %token NIL
! %token IF THEN ELSE ELSEIF WHILE DO REPEAT UNTIL CASE OF END
  %token RETURN
  %token LOCAL
  %token FUNCTION
  %token DOTS
+ %token ARROW
  %token <vFloat> NUMBER
  %token <vWord>  STRING
  %token <pTStr>  NAME 
***************
*** 515,520 ****
--- 516,523 ----
  stat   : IF expr1 THEN PrepJump block PrepJump elsepart END
  	{ codeIf($4, $6); }
  
+        | CASE expr1 OF case_body END
+ 
         | WHILE {$<vLong>$=pc;} expr1 DO PrepJump block PrepJump END
         {
          basepc[$5] = IFFJMP;
***************
*** 553,558 ****
--- 556,569 ----
  	{ codeIf($4, $6); }
           ;
       
+ case_body : '|' {code_byte(DUP);} expr1 {code_byte(EQOP);} PrepJump ARROW 
+                 {code_byte(POP);} block PrepJump case_body
+                     { codeIf($5, $9); }
+                 /* should support multiple exprs */
+           | ELSE ARROW {code_byte(POP);} block 
+           | /* empty */ {code_byte(POP); /* should code for fallback here */ }
+           ;
+ 
  block    : {$<vInt>$ = nlocalvar;} statlist ret 
           {
  	  if (nlocalvar != $<vInt>1)