lua-users home
lua-l archive

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


On Thu, Jun 11, 2009 at 12:45 PM, Michael Newberry wrote:
> it would be nice to have more detailed compiler messages.
> For example, considering assignment instead of a test:
>
>   a = 1
>   if a = 1 then foo end
>
> gives
>   Error: Loading Module 'Script Document1': :2: `then' expected near `='

The error does make sense in a way.  "a" forms a complete expression.
"if <exp>" should be followed by "then".

But you are correct in that the problem almost certainly lies with an
incorrect expression rather than the "then".  Here's a patch:

--- lua-5.1.4/src/lparser.c
+++ lua-5.1.4-better-errors/src/lparser.c
@@ -1132,6 +1132,8 @@
   int condexit;
   luaX_next(ls);  /* skip IF or ELSEIF */
   condexit = cond(ls);
+  if (ls->t.token == '=')
+    error_expected(ls, TK_EQ);
   checknext(ls, TK_THEN);
   block(ls);  /* `then' part */
   return condexit;

Example:

  if a = 1 then print() end
  --> stdin:1: '==' expected near '='

> Here's another one:
>
>   `=' expected near `ot'
>
> is thrown by
>
>   ifn ot CMyClass then

That form is more difficult in general.  Unless the compiler guesses
than "ifn" really means "if", then it instead sees something
equivalent to "a b c then", just with different letters.  "a b c then"
is interpreted as a statement.  It is a statement that starts with a
primary expression "a" (i.e. lparser.c:exprstat).  That primary
expression is not followed by a comma, so it can't be an expression
list in an assignment (i.e. lparser.c:assignment).  Neither is it a
function call.  The only thing left is an assignment, but it can't be
that either since the primary expression is not followed by "=".  It
only reports not seeing "=".

You might do this patch on assignments:

--- lua-5.1.4/src/lparser.c
+++ lua-5.1.4-better-errors-2/src/lparser.c
@@ -944,7 +944,12 @@
   }
   else {  /* assignment -> `=' explist1 */
     int nexps;
-    checknext(ls, '=');
+    if (ls->t.token != '=') {
+      luaX_syntaxerror(ls,
+        luaO_pushfstring(ls->L, LUA_QL(",") ", " LUA_QL("(") ", or "
+                                LUA_QL("=") " expected"));
+    }
+    luaX_next(ls);
     nexps = explist1(ls, &e);
     if (nexps != nvars) {
       adjust_assign(ls, nvars, nexps, &e);

Example:

  ifn ot CMyClass then print() end
  --> stdin:1: ',', '(', or '=' expected near 'ot'

though I suspect it's now more fragile (less locality) if you later
want to patch Lua with some syntax extension.  Perhaps your extension
will allow some other token to following prefix expressions, and you
are expected to remember to fix the above code in the assignment
function accordingly.

Going further with patching,

@@ -1225,6 +1230,13 @@
   /* stat -> func | assignment */
   FuncState *fs = ls->fs;
   struct LHS_assign v;
+  luaX_lookahead(ls);
+  if (ls->t.token == TK_NAME && ls->lookahead.token == TK_NAME &&
+      ls->t.seminfo.ts->tsv.len > 2 &&
+      strstr(getstr(ls->t.seminfo.ts), "if") == getstr(ls->t.seminfo.ts)
+  ) {
+    luaX_syntaxerror(ls, "did you mean 'if'?");
+  }
   primaryexp(ls, &v.v);
   if (v.v.k == VCALL)  /* stat -> func */
     SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */

gives something like you want:

  ifn ot CMyClass then print() end
  --> stdin:1: did you mean 'if'? near 'ot'

Maybe the better solution, to avoid spaghetti code is to backtrack on
syntax errors, assign probabilities to error messages, and report the
errors in decreasing order of probability.