commit 014a09c5095be3ef11366530e4630ee817a526a7
parent b62228297372c7b24b6661ac1bdd7df2e8ece64e
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 28 Jun 2000 17:20:44 -0300
better error messages
Diffstat:
M | lcode.c | | | 108 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | lcode.h | | | 7 | +++++-- |
M | ldebug.c | | | 148 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | ldebug.h | | | 8 | ++++---- |
M | ldo.c | | | 8 | ++++---- |
M | ldo.h | | | 4 | ++-- |
M | lobject.h | | | 8 | ++++---- |
M | lparser.c | | | 8 | ++++---- |
M | lparser.h | | | 3 | ++- |
M | lvm.c | | | 32 | ++++++++++++++++---------------- |
10 files changed, 230 insertions(+), 104 deletions(-)
diff --git a/lcode.c b/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 1.38 2000/06/21 18:13:56 roberto Exp roberto $
+** $Id: lcode.c,v 1.39 2000/06/26 19:28:31 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -423,12 +423,9 @@ int luaK_code1 (FuncState *fs, OpCode o, int arg1) {
}
-#define VD 100 /* flag for variable delta */
-
-
int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
Instruction i = previous_instruction(fs);
- int delta = luaK_opproperties[o].delta;
+ int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop;
int optm = 0; /* 1 when there is an optimization */
switch (o) {
case OP_CLOSURE: {
@@ -621,7 +618,7 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
case iS: i = CREATE_S(o, arg1); break;
case iAB: i = CREATE_AB(o, arg1, arg2); break;
}
- if (fs->f->debug) {
+ if (fs->debug) {
LexState *ls = fs->ls;
luaX_checklimit(ls, ls->lastline, MAXARG_U, "lines in a chunk");
luaM_growvector(fs->L, fs->f->lines, fs->pc, 1, int, "??", MAXARG_U);
@@ -636,53 +633,54 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
const struct OpProperties luaK_opproperties[NUM_OPCODES] = {
- {iO, 0}, /* OP_END */
- {iU, 0}, /* OP_RETURN */
- {iAB, 0}, /* OP_CALL */
- {iAB, 0}, /* OP_TAILCALL */
- {iU, VD}, /* OP_PUSHNIL */
- {iU, VD}, /* OP_POP */
- {iS, 1}, /* OP_PUSHINT */
- {iU, 1}, /* OP_PUSHSTRING */
- {iU, 1}, /* OP_PUSHNUM */
- {iU, 1}, /* OP_PUSHNEGNUM */
- {iU, 1}, /* OP_PUSHUPVALUE */
- {iU, 1}, /* OP_GETLOCAL */
- {iU, 1}, /* OP_GETGLOBAL */
- {iO, -1}, /* OP_GETTABLE */
- {iU, 0}, /* OP_GETDOTTED */
- {iU, 0}, /* OP_GETINDEXED */
- {iU, 1}, /* OP_PUSHSELF */
- {iU, 1}, /* OP_CREATETABLE */
- {iU, -1}, /* OP_SETLOCAL */
- {iU, -1}, /* OP_SETGLOBAL */
- {iAB, VD}, /* OP_SETTABLE */
- {iAB, VD}, /* OP_SETLIST */
- {iU, VD}, /* OP_SETMAP */
- {iO, -1}, /* OP_ADD */
- {iS, 0}, /* OP_ADDI */
- {iO, -1}, /* OP_SUB */
- {iO, -1}, /* OP_MULT */
- {iO, -1}, /* OP_DIV */
- {iO, -1}, /* OP_POW */
- {iU, VD}, /* OP_CONCAT */
- {iO, 0}, /* OP_MINUS */
- {iO, 0}, /* OP_NOT */
- {iS, -2}, /* OP_JMPNE */
- {iS, -2}, /* OP_JMPEQ */
- {iS, -2}, /* OP_JMPLT */
- {iS, -2}, /* OP_JMPLE */
- {iS, -2}, /* OP_JMPGT */
- {iS, -2}, /* OP_JMPGE */
- {iS, -1}, /* OP_JMPT */
- {iS, -1}, /* OP_JMPF */
- {iS, -1}, /* OP_JMPONT */
- {iS, -1}, /* OP_JMPONF */
- {iS, 0}, /* OP_JMP */
- {iO, 1}, /* OP_PUSHNILJMP */
- {iS, 0}, /* OP_FORPREP */
- {iS, -3}, /* OP_FORLOOP */
- {iS, 3}, /* OP_LFORPREP */
- {iS, -4}, /* OP_LFORLOOP */
- {iAB, VD} /* OP_CLOSURE */
+ {iO, 0, 0}, /* OP_END */
+ {iU, 0, 0}, /* OP_RETURN */
+ {iAB, 0, 0}, /* OP_CALL */
+ {iAB, 0, 0}, /* OP_TAILCALL */
+ {iU, VD, 0}, /* OP_PUSHNIL */
+ {iU, VD, 0}, /* OP_POP */
+ {iS, 1, 0}, /* OP_PUSHINT */
+ {iU, 1, 0}, /* OP_PUSHSTRING */
+ {iU, 1, 0}, /* OP_PUSHNUM */
+ {iU, 1, 0}, /* OP_PUSHNEGNUM */
+ {iU, 1, 0}, /* OP_PUSHUPVALUE */
+ {iU, 1, 0}, /* OP_GETLOCAL */
+ {iU, 1, 0}, /* OP_GETGLOBAL */
+ {iO, 1, 2}, /* OP_GETTABLE */
+ {iU, 1, 1}, /* OP_GETDOTTED */
+ {iU, 1, 1}, /* OP_GETINDEXED */
+ {iU, 2, 1}, /* OP_PUSHSELF */
+ {iU, 1, 0}, /* OP_CREATETABLE */
+ {iU, 0, 1}, /* OP_SETLOCAL */
+ {iU, 0, 1}, /* OP_SETGLOBAL */
+ {iAB, VD, 0}, /* OP_SETTABLE */
+ {iAB, VD, 0}, /* OP_SETLIST */
+ {iU, VD, 0}, /* OP_SETMAP */
+ {iO, 1, 2}, /* OP_ADD */
+ {iS, 1, 1}, /* OP_ADDI */
+ {iO, 1, 2}, /* OP_SUB */
+ {iO, 1, 2}, /* OP_MULT */
+ {iO, 1, 2}, /* OP_DIV */
+ {iO, 1, 2}, /* OP_POW */
+ {iU, VD, 0}, /* OP_CONCAT */
+ {iO, 1, 1}, /* OP_MINUS */
+ {iO, 1, 1}, /* OP_NOT */
+ {iS, 0, 2}, /* OP_JMPNE */
+ {iS, 0, 2}, /* OP_JMPEQ */
+ {iS, 0, 2}, /* OP_JMPLT */
+ {iS, 0, 2}, /* OP_JMPLE */
+ {iS, 0, 2}, /* OP_JMPGT */
+ {iS, 0, 2}, /* OP_JMPGE */
+ {iS, 0, 1}, /* OP_JMPT */
+ {iS, 0, 1}, /* OP_JMPF */
+ {iS, 0, 1}, /* OP_JMPONT */
+ {iS, 0, 1}, /* OP_JMPONF */
+ {iS, 0, 0}, /* OP_JMP */
+ {iO, 1, 0}, /* OP_PUSHNILJMP */
+ {iS, 0, 0}, /* OP_FORPREP */
+ {iS, 0, 3}, /* OP_FORLOOP */
+ {iS, 3, 0}, /* OP_LFORPREP */
+ {iS, 0, 4}, /* OP_LFORLOOP */
+ {iAB, VD, 0} /* OP_CLOSURE */
};
+
diff --git a/lcode.h b/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.13 2000/05/22 18:44:46 roberto Exp roberto $
+** $Id: lcode.h,v 1.14 2000/06/16 17:51:40 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -22,9 +22,12 @@
enum Mode {iO, iU, iS, iAB}; /* instruction format */
+#define VD 100 /* flag for variable delta */
+
extern const struct OpProperties {
char mode;
- signed char delta;
+ unsigned char push;
+ unsigned char pop;
} luaK_opproperties[];
diff --git a/ldebug.c b/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 1.23 2000/06/12 13:52:05 roberto Exp roberto $
+** $Id: ldebug.c,v 1.24 2000/06/26 19:28:31 roberto Exp roberto $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -13,10 +13,12 @@
#include "lapi.h"
#include "lauxlib.h"
+#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lobject.h"
+#include "lopcodes.h"
#include "lstate.h"
#include "ltable.h"
#include "ltm.h"
@@ -97,6 +99,13 @@ static int lua_nups (StkId f) {
}
+static int lua_currentpc (StkId f) {
+ CallInfo *ci = infovalue(f);
+ LUA_ASSERT(L, ttype(f) == TAG_LMARK, "function has no pc");
+ return (*ci->pc - 1) - ci->func->f.l->code;
+}
+
+
static int lua_currentline (StkId f) {
if (ttype(f) != TAG_LMARK)
return -1; /* only active lua functions have current-line information */
@@ -104,15 +113,11 @@ static int lua_currentline (StkId f) {
CallInfo *ci = infovalue(f);
int *lines = ci->func->f.l->lines;
if (!lines) return -1; /* no static debug information */
- else return lines[ci->pc];
+ else return lines[lua_currentpc(f)];
}
}
-static int lua_currentpc (StkId f) {
- return infovalue(f)->pc;
-}
-
static Proto *getluaproto (StkId f) {
return (ttype(f) == TAG_LMARK) ? infovalue(f)->func->f.l : NULL;
@@ -225,17 +230,136 @@ int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
}
+/*
+** {======================================================
+** Symbolic Execution
+** =======================================================
+*/
+
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
+ int stack[MAXSTACK]; /* stores last instruction that changes each value */
+ const Instruction *code = pt->code;
+ int top = pt->numparams;
+ int pc = 0;
+ if (pt->is_vararg) /* varargs? */
+ top++; /* `arg' */
+ while (pc < lastpc) {
+ const Instruction i = code[pc++];
+ switch (GET_OPCODE(i)) {
+ case OP_CALL: {
+ int nresults = GETARG_B(i);
+ if (nresults == MULT_RET) nresults = 1;
+ top = GETARG_A(i);
+ while (nresults--)
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_PUSHNIL: {
+ int n;
+ for (n=0; n<GETARG_U(i); n++)
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_POP: {
+ top -= GETARG_U(i);
+ break;
+ }
+ case OP_SETTABLE:
+ case OP_SETLIST: {
+ top -= GETARG_B(i);
+ break;
+ }
+ case OP_SETMAP: {
+ top -= 2*GETARG_U(i);
+ break;
+ }
+ case OP_CONCAT: {
+ top -= GETARG_U(i);
+ stack[top++] = pc-1;
+ break;
+ }
+ case OP_JMPONT:
+ case OP_JMPONF: {
+ int newpc = pc + GETARG_S(i);
+ if (newpc >= lastpc) {
+ stack[top-1] = pc-1; /* value generated by or-and */
+ pc = newpc; /* do the jump */
+ }
+ else
+ top--; /* original code did not jump; condition was false */
+ break;
+ }
+ case OP_PUSHNILJMP: {
+ break; /* do not `push', to compensate next instruction */
+ }
+ case OP_CLOSURE: {
+ top -= GETARG_B(i);
+ stack[top++] = pc-1;
+ break;
+ }
+ default: {
+ int n;
+ LUA_ASSERT(NULL, luaK_opproperties[GET_OPCODE(i)].push != VD,
+ "invalid opcode for default");
+ top -= luaK_opproperties[GET_OPCODE(i)].pop;
+ for (n=0; n<luaK_opproperties[GET_OPCODE(i)].push; n++)
+ stack[top++] = pc-1;
+ }
+ }
+ }
+ return code[stack[stackpos]];
+}
+
+
+static const char *getname (lua_State *L, StkId obj, const char **name) {
+ StkId func = aux_stackedfunction(L, 0, obj);
+ if (func == NULL || ttype(func) != TAG_LMARK)
+ return NULL; /* not a Lua function */
+ else {
+ Proto *p = infovalue(func)->func->f.l;
+ int pc = lua_currentpc(func);
+ int stackpos = obj - (func+1); /* func+1 == function base */
+ Instruction i = luaG_symbexec(p, pc, stackpos);
+ switch (GET_OPCODE(i)) {
+ case OP_GETGLOBAL: {
+ *name = p->kstr[GETARG_U(i)]->str;
+ return "global";
+ }
+ case OP_GETLOCAL: {
+ *name = luaF_getlocalname(p, GETARG_U(i)+1, pc);
+ return (*name) ? "local" : NULL;
+ }
+ case OP_PUSHSELF:
+ case OP_GETDOTTED: {
+ *name = p->kstr[GETARG_U(i)]->str;
+ return "field";
+ }
+ default:
+ return NULL; /* no usefull name found */
+ }
+ }
+}
+
+
+/* }====================================================== */
+
-static void call_index_error (lua_State *L, TObject *o, const char *v) {
- luaL_verror(L, "attempt to %.10s a %.10s value", v, lua_type(L, o));
+static void call_index_error (lua_State *L, StkId o, const char *op,
+ const char *tp) {
+ const char *name;
+ const char *kind = getname(L, o, &name);
+ if (kind)
+ luaL_verror(L, "%s `%s' is not a %s", kind, name, tp);
+ else
+ luaL_verror(L, "attempt to %.10s a %.10s value", op, lua_type(L, o));
}
-void luaG_callerror (lua_State *L, TObject *func) {
- call_index_error(L, func, "call");
+void luaG_callerror (lua_State *L, StkId func) {
+ call_index_error(L, func, "call", "function");
}
-void luaG_indexerror (lua_State *L, TObject *t) {
- call_index_error(L, t, "index");
+void luaG_indexerror (lua_State *L, StkId t) {
+ call_index_error(L, t, "index", "table");
}
diff --git a/ldebug.h b/ldebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: $
+** $Id: ldebug.h,v 1.1 2000/01/14 17:15:44 roberto Exp roberto $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -8,12 +8,12 @@
#define ldebug_h
-#include "lobject.h"
+#include "lstate.h"
#include "luadebug.h"
-void luaG_callerror (lua_State *L, TObject *func);
-void luaG_indexerror (lua_State *L, TObject *t);
+void luaG_callerror (lua_State *L, StkId func);
+void luaG_indexerror (lua_State *L, StkId t);
#endif
diff --git a/ldo.c b/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 1.79 2000/06/16 17:16:34 roberto Exp roberto $
+** $Id: ldo.c,v 1.80 2000/06/26 19:28:31 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -103,7 +103,7 @@ void luaD_openstack (lua_State *L, StkId pos) {
}
-void luaD_lineHook (lua_State *L, StkId func, int line) {
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) {
if (L->allowhooks) {
lua_Debug ar;
struct C_Lua_Stack oldCLS = L->Cstack;
@@ -113,7 +113,7 @@ void luaD_lineHook (lua_State *L, StkId func, int line) {
ar.event = "line";
ar.currentline = line;
L->allowhooks = 0; /* cannot call hooks inside a hook */
- (*L->linehook)(L, &ar);
+ (*linehook)(L, &ar);
L->allowhooks = 1;
L->top = old_top;
L->Cstack = oldCLS;
@@ -187,7 +187,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
case TAG_LCLOSURE: {
CallInfo ci;
ci.func = clvalue(func);
- ci.pc = 0;
+ ci.line = 0;
ttype(func) = TAG_LMARK;
infovalue(func) = &ci;
if (callhook)
diff --git a/ldo.h b/ldo.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.h,v 1.19 2000/03/29 20:19:20 roberto Exp roberto $
+** $Id: ldo.h,v 1.20 2000/04/14 18:12:35 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -22,7 +22,7 @@
void luaD_init (lua_State *L, int stacksize);
void luaD_adjusttop (lua_State *L, StkId base, int extra);
void luaD_openstack (lua_State *L, StkId pos);
-void luaD_lineHook (lua_State *L, StkId func, int line);
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook);
void luaD_call (lua_State *L, StkId func, int nResults);
void luaD_callTM (lua_State *L, const TObject *f, int nParams, int nResults);
int luaD_protectedrun (lua_State *L);
diff --git a/lobject.h b/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 1.67 2000/06/08 18:27:13 roberto Exp roberto $
+** $Id: lobject.h,v 1.68 2000/06/26 19:28:31 roberto Exp roberto $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -122,7 +122,6 @@ typedef struct Proto {
int *lines; /* source line that generated each opcode */
int lineDefined;
TString *source;
- int debug; /* flag for debug information */
int numparams;
int is_vararg;
int maxstacksize;
@@ -171,9 +170,10 @@ typedef struct Hash {
** informations about a call (for debugging)
*/
typedef struct CallInfo {
- int pc; /* current pc of called function */
- int line; /* current line */
struct Closure *func; /* function being called */
+ const Instruction **pc; /* current pc of called function */
+ int lastpc; /* last pc traced */
+ int line; /* current line */
} CallInfo;
diff --git a/lparser.c b/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 1.99 2000/06/26 19:28:31 roberto Exp roberto $
+** $Id: lparser.c,v 1.100 2000/06/28 17:06:07 roberto Exp roberto $
** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -154,7 +154,7 @@ static int checkname (LexState *ls) {
static void luaI_registerlocalvar (LexState *ls, TString *varname, int pc) {
FuncState *fs = ls->fs;
- if (fs->f->debug) {
+ if (fs->debug) {
Proto *f = fs->f;
luaM_growvector(ls->L, f->locvars, fs->nvars, 1, LocVar, "", MAX_INT);
f->locvars[fs->nvars].varname = varname;
@@ -359,7 +359,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z) {
luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
open_func(&lexstate, &funcstate);
next(&lexstate); /* read first token */
- funcstate.f->debug = L->debug; /* previous `next' may scan a pragma */
+ funcstate.debug = L->debug; /* previous `next' may scan a pragma */
chunk(&lexstate);
check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected");
close_func(&lexstate);
@@ -1085,7 +1085,7 @@ static void body (LexState *ls, int needself, int line) {
FuncState new_fs;
open_func(ls, &new_fs);
new_fs.f->lineDefined = line;
- new_fs.f->debug = ls->L->debug;
+ new_fs.debug = ls->L->debug;
check(ls, '(');
if (needself) {
new_localvarstr(ls, "self", 0);
diff --git a/lparser.h b/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.18 2000/06/21 18:13:56 roberto Exp roberto $
+** $Id: lparser.h,v 1.19 2000/06/26 19:28:31 roberto Exp roberto $
** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -47,6 +47,7 @@ typedef struct FuncState {
int stacklevel; /* number of values on activation register */
int nlocalvar; /* number of active local variables */
int nupvalues; /* number of upvalues */
+ int debug; /* flag for debug information */
int nvars; /* number of entries in f->locvars */
struct Breaklabel *bl; /* chain of breakable blocks */
expdesc upvalues[MAXUPVALUES]; /* upvalues */
diff --git a/lvm.c b/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 1.117 2000/06/26 19:28:31 roberto Exp roberto $
+** $Id: lvm.c,v 1.118 2000/06/27 19:00:36 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -67,20 +67,19 @@ int luaV_tostring (lua_State *L, TObject *obj) { /* LUA_NUMBER */
}
-static void traceexec (lua_State *L, StkId base, int pc, StkId top) {
+static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) {
CallInfo *ci = infovalue(base-1);
- int oldpc = ci->pc;
- ci->pc = pc;
- if (L->linehook && ci->func->f.l->debug) {
- int *lines = ci->func->f.l->lines;
- LUA_ASSERT(L, lines, "must have debug information");
- /* calls linehook when jumps back (loop) or enters a new line */
- if (pc <= oldpc || lines[pc] != ci->line) {
+ int *lines = ci->func->f.l->lines;
+ int pc = (*ci->pc - 1) - ci->func->f.l->code;
+ if (lines) {
+ /* calls linehook when enters a new line or jumps back (loop) */
+ if (lines[pc] != ci->line || pc <= ci->lastpc) {
ci->line = lines[pc];
L->top = top;
- luaD_lineHook(L, base-2, lines[pc]);
+ luaD_lineHook(L, base-2, lines[pc], linehook);
}
}
+ ci->lastpc = pc;
}
@@ -113,7 +112,7 @@ void luaV_Lclosure (lua_State *L, Proto *l, int nelems) {
** Receives the table at top-2 and the index at top-1.
*/
void luaV_gettable (lua_State *L, StkId top) {
- TObject *table = top-2;
+ StkId table = top-2;
const TObject *im;
if (ttype(table) != TAG_TABLE) { /* not a table, get gettable TM */
im = luaT_getimbyObj(L, table, IM_GETTABLE);
@@ -348,7 +347,8 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
StkId top; /* keep top local, for performance */
const Instruction *pc = tf->code;
TString **kstr = tf->kstr;
- int debug = tf->debug;
+ lua_Hook linehook = L->linehook;
+ infovalue(base-1)->pc = &pc;
luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK);
if (tf->is_vararg) { /* varargs? */
adjust_varargs(L, base, tf->numparams);
@@ -359,9 +359,9 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
top = L->top;
/* main loop of interpreter */
for (;;) {
- if (debug)
- traceexec(L, base, pc - tf->code, top);
- {const Instruction i = *pc++;
+ const Instruction i = *pc++;
+ if (linehook)
+ traceexec(L, base, top, linehook);
switch (GET_OPCODE(i)) {
case OP_END:
@@ -705,5 +705,5 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
break;
}
- }}
+ }
}