lua-users home
lua-l archive

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


Luiz Henrique de Figueiredo wrote:
>
> > Not sure when the change was made, but I noticed that Lua 5.2.0
> > allows the following syntax:
> > 
> > print
> > (
> >     'foo'
> > )
> > 
> > Is that change on purpose? Or accidental?
> 
> On purpose. The introduction on empty statements help this because
> you can now write
> 	; (exp)...
> for a statement that starts with an open parenthesis.

I'm glad that this irk has finally been removed.

Checking my other pet-peeve I noticed that it's still there:

  print("%d":format(42))    --> error: ')' expected near ':'
  print(("%d"):format(42))  --> 42

I still have to add these superfluous parentheses around the string.
As far as I can see, there's no real reason for the parentheses.

I've attached a patch to remove this requirement (patch1).  With it
the first example works as expected.

Additionally, it enables stuff like:

  ;{print}[1]"foo"   --> foo

But honestly, I was never comfortable with arbitrary expressions for
expression statements.  If you forget the semicolon the parser won't
detect it in a lot of cases.

As there's already a syntax incompatibility between 5.1 and 5.2 in this
regard, I would suggest to limit statement expressions to those that
start with an identifier.  To make expression statements like the above
work, add an identity function (i.e Id) to the base lib:

  Id{print}[1]"foo"   --> foo

I've attached another tiny patch that shows what I mean (patch2).
With it it's pretty clear where a statement begin: either with a keyword
(if, for, return, ...) or with an identifier - point.  No complicated
analysis needed. 

Ciao, ET.

PS: I didn't check patch1 very much - the first time I did it was about
    10 years ago and I may have missed something by now.
commit 2bc625324fa6b71e32b35595be77ce1f8ed2ba43
Author: Edgar Toernig <froese@gmx.de>
Date:   Sun Nov 21 14:51:36 2010 +0100

    parser: remove prefixexp - enables "%d":format(3)

diff --git a/src/lparser.c b/src/lparser.c
index 3524b9b..483a305 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -730,36 +730,14 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
 ** =======================================================================
 */
 
-
-static void prefixexp (LexState *ls, expdesc *v) {
-  /* prefixexp -> NAME | '(' expr ')' */
-  switch (ls->t.token) {
-    case '(': {
-      int line = ls->linenumber;
-      luaX_next(ls);
-      expr(ls, v);
-      check_match(ls, ')', '(', line);
-      luaK_dischargevars(ls->fs, v);
-      return;
-    }
-    case TK_NAME: {
-      singlevar(ls, v);
-      return;
-    }
-    default: {
-      luaX_syntaxerror(ls, "unexpected symbol");
-      return;
-    }
-  }
-}
-
+static void simpleexp (LexState *ls, expdesc *v);
 
 static void primaryexp (LexState *ls, expdesc *v) {
   /* primaryexp ->
-        prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
+        simpleexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
   FuncState *fs = ls->fs;
   int line = ls->linenumber;
-  prefixexp(ls, v);
+  simpleexp(ls, v);
   for (;;) {
     switch (ls->t.token) {
       case '.': {  /* fieldsel */
@@ -833,8 +811,20 @@ static void simpleexp (LexState *ls, expdesc *v) {
       body(ls, v, 0, ls->linenumber);
       return;
     }
+    case '(': {
+      int line = ls->linenumber;
+      luaX_next(ls);
+      expr(ls, v);
+      check_match(ls, ')', '(', line);
+      luaK_dischargevars(ls->fs, v);
+      return;
+    }
+    case TK_NAME: {
+      singlevar(ls, v);
+      return;
+    }
     default: {
-      primaryexp(ls, v);
+      luaX_syntaxerror(ls, "unexpected symbol");
       return;
     }
   }
@@ -889,7 +879,7 @@ static const struct {
 
 
 /*
-** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
+** subexpr -> (primaryexp | unop subexpr) { binop subexpr }
 ** where `binop' is any binary operator with a priority higher than `limit'
 */
 static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
@@ -903,7 +893,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
     subexpr(ls, v, UNARY_PRIORITY);
     luaK_prefix(ls->fs, uop, v, line);
   }
-  else simpleexp(ls, v);
+  else primaryexp(ls, v);
   /* expand while operators have priorities higher than `limit' */
   op = getbinopr(ls->t.token);
   while (op != OPR_NOBINOPR && priority[op].left > limit) {
commit 66be62f34ca53452d8c460a8736806abfd69ef25
Author: Edgar Toernig <froese@gmx.de>
Date:   Sun Nov 21 14:56:29 2010 +0100

    parser: statement expressions have to start with TK_NAME
    
    Additionally add identity function (Id) to allow complex
    expression statements (like: Id{print}[1]"foo").

diff --git a/src/lbaselib.c b/src/lbaselib.c
index 1553c1d..b40ad5b 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -463,6 +463,10 @@ static int luaB_newproxy (lua_State *L) {
   return 1;
 }
 
+static int luaB_id (lua_State *L) {
+  return lua_gettop(L);
+}
+
 
 static const luaL_Reg base_funcs[] = {
   {"assert", luaB_assert},
@@ -490,6 +494,7 @@ static const luaL_Reg base_funcs[] = {
   {"tostring", luaB_tostring},
   {"type", luaB_type},
   {"xpcall", luaB_xpcall},
+  {"Id", luaB_id},
   {NULL, NULL}
 };
 
diff --git a/src/lparser.c b/src/lparser.c
index 483a305..71ce299 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1385,10 +1385,14 @@ static int statement (LexState *ls) {
       breakstat(ls);
       return 1;  /* must be last statement */
     }
-    default: {  /* stat -> func | assignment */
+    case TK_NAME: {   /* stat -> func | assignment */
       exprstat(ls);
       return 0;
     }
+    default: {
+      luaX_syntaxerror(ls, "statement expected");
+      return 0;
+    }
   }
 }